aipp 0.1.3 → 0.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 +4 -4
- data/.gitignore +2 -0
- data/.ruby-version +1 -1
- data/.yardopts +3 -0
- data/CHANGELOG.md +25 -10
- data/README.md +116 -27
- data/aipp.gemspec +4 -2
- data/exe/aip2aixm +1 -50
- data/exe/aip2ofmx +11 -0
- data/lib/aipp.rb +20 -3
- data/lib/aipp/aip.rb +63 -0
- data/lib/aipp/airac.rb +17 -9
- data/lib/aipp/executable.rb +82 -0
- data/lib/aipp/parser.rb +97 -0
- data/lib/aipp/progress.rb +40 -0
- data/lib/aipp/refinements.rb +91 -28
- data/lib/aipp/regions/LF/ENR-2.1.rb +89 -0
- data/lib/aipp/regions/LF/ENR-4.1.rb +101 -0
- data/lib/aipp/regions/LF/ENR-4.3.rb +26 -0
- data/lib/aipp/regions/LF/ENR-5.1.rb +65 -0
- data/lib/aipp/regions/LF/helper.rb +177 -0
- data/lib/aipp/t_hash.rb +46 -0
- data/lib/aipp/version.rb +1 -1
- data/spec/lib/aipp/airac_spec.rb +3 -3
- data/spec/lib/aipp/refinements_spec.rb +97 -27
- data/spec/lib/aipp/t_hash_spec.rb +44 -0
- metadata +50 -14
- data/lib/aipp/loader.rb +0 -52
- data/lib/aipp/parsers/LF/AD-1.5.rb +0 -128
- data/lib/aipp/parsers/LF/ENR-4.1.rb +0 -105
- data/lib/aipp/parsers/LF/ENR-4.3.rb +0 -32
- data/lib/aipp/parsers/LF/ENR-5.1.rb +0 -134
- data/lib/aipp/parsers/LF/helpers/html.rb +0 -11
- data/lib/aipp/parsers/LF/helpers/url.rb +0 -15
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe AIPP::THash do
|
4
|
+
context "non-circular dependencies" do
|
5
|
+
subject do
|
6
|
+
AIPP::THash[
|
7
|
+
dns: %i(net),
|
8
|
+
webserver: %i(dns logger),
|
9
|
+
net: [],
|
10
|
+
logger: []
|
11
|
+
]
|
12
|
+
end
|
13
|
+
|
14
|
+
describe :tsort do
|
15
|
+
it "must compile the overall dependency list" do
|
16
|
+
subject.tsort.must_equal %i(net dns logger webserver)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "must compile partial dependency lists" do
|
20
|
+
subject.tsort(:dns).must_equal %i(net dns)
|
21
|
+
subject.tsort(:logger).must_equal %i(logger)
|
22
|
+
subject.tsort(:webserver).must_equal %i(net dns logger webserver)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "circular dependencies" do
|
28
|
+
subject do
|
29
|
+
AIPP::THash[
|
30
|
+
dns: %i(net),
|
31
|
+
webserver: %i(dns logger),
|
32
|
+
net: %i(dns),
|
33
|
+
logger: []
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
describe :tsort do
|
38
|
+
it "must raise cyclic dependency error" do
|
39
|
+
-> { subject.tsort }.must_raise TSort::Cyclic
|
40
|
+
-> { subject.tsort(:dns) }.must_raise TSort::Cyclic
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aipp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sven Schwyn
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -131,7 +131,7 @@ dependencies:
|
|
131
131
|
version: '0'
|
132
132
|
- - ">="
|
133
133
|
- !ruby/object:Gem::Version
|
134
|
-
version: 0.2
|
134
|
+
version: 0.3.2
|
135
135
|
type: :runtime
|
136
136
|
prerelease: false
|
137
137
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -141,7 +141,7 @@ dependencies:
|
|
141
141
|
version: '0'
|
142
142
|
- - ">="
|
143
143
|
- !ruby/object:Gem::Version
|
144
|
-
version: 0.2
|
144
|
+
version: 0.3.2
|
145
145
|
- !ruby/object:Gem::Dependency
|
146
146
|
name: nokogiri
|
147
147
|
requirement: !ruby/object:Gem::Requirement
|
@@ -162,14 +162,28 @@ dependencies:
|
|
162
162
|
requirements:
|
163
163
|
- - "~>"
|
164
164
|
- !ruby/object:Gem::Version
|
165
|
-
version: '
|
165
|
+
version: '2'
|
166
166
|
type: :runtime
|
167
167
|
prerelease: false
|
168
168
|
version_requirements: !ruby/object:Gem::Requirement
|
169
169
|
requirements:
|
170
170
|
- - "~>"
|
171
171
|
- !ruby/object:Gem::Version
|
172
|
-
version: '
|
172
|
+
version: '2'
|
173
|
+
- !ruby/object:Gem::Dependency
|
174
|
+
name: colorize
|
175
|
+
requirement: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - "~>"
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
180
|
+
type: :runtime
|
181
|
+
prerelease: false
|
182
|
+
version_requirements: !ruby/object:Gem::Requirement
|
183
|
+
requirements:
|
184
|
+
- - "~>"
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0'
|
173
187
|
- !ruby/object:Gem::Dependency
|
174
188
|
name: pry
|
175
189
|
requirement: !ruby/object:Gem::Requirement
|
@@ -184,17 +198,33 @@ dependencies:
|
|
184
198
|
- - "~>"
|
185
199
|
- !ruby/object:Gem::Version
|
186
200
|
version: '0'
|
201
|
+
- !ruby/object:Gem::Dependency
|
202
|
+
name: pry-rescue
|
203
|
+
requirement: !ruby/object:Gem::Requirement
|
204
|
+
requirements:
|
205
|
+
- - "~>"
|
206
|
+
- !ruby/object:Gem::Version
|
207
|
+
version: '1'
|
208
|
+
type: :runtime
|
209
|
+
prerelease: false
|
210
|
+
version_requirements: !ruby/object:Gem::Requirement
|
211
|
+
requirements:
|
212
|
+
- - "~>"
|
213
|
+
- !ruby/object:Gem::Version
|
214
|
+
version: '1'
|
187
215
|
description: Parser for Aeronautical Information Publications (AIP).
|
188
216
|
email:
|
189
217
|
- ruby@bitcetera.com
|
190
218
|
executables:
|
191
219
|
- aip2aixm
|
220
|
+
- aip2ofmx
|
192
221
|
extensions: []
|
193
222
|
extra_rdoc_files: []
|
194
223
|
files:
|
195
224
|
- ".gitignore"
|
196
225
|
- ".ruby-version"
|
197
226
|
- ".travis.yml"
|
227
|
+
- ".yardopts"
|
198
228
|
- CHANGELOG.md
|
199
229
|
- Gemfile
|
200
230
|
- Guardfile
|
@@ -203,19 +233,24 @@ files:
|
|
203
233
|
- Rakefile
|
204
234
|
- aipp.gemspec
|
205
235
|
- exe/aip2aixm
|
236
|
+
- exe/aip2ofmx
|
206
237
|
- lib/aipp.rb
|
238
|
+
- lib/aipp/aip.rb
|
207
239
|
- lib/aipp/airac.rb
|
208
|
-
- lib/aipp/
|
209
|
-
- lib/aipp/
|
210
|
-
- lib/aipp/
|
211
|
-
- lib/aipp/parsers/LF/ENR-4.3.rb
|
212
|
-
- lib/aipp/parsers/LF/ENR-5.1.rb
|
213
|
-
- lib/aipp/parsers/LF/helpers/html.rb
|
214
|
-
- lib/aipp/parsers/LF/helpers/url.rb
|
240
|
+
- lib/aipp/executable.rb
|
241
|
+
- lib/aipp/parser.rb
|
242
|
+
- lib/aipp/progress.rb
|
215
243
|
- lib/aipp/refinements.rb
|
244
|
+
- lib/aipp/regions/LF/ENR-2.1.rb
|
245
|
+
- lib/aipp/regions/LF/ENR-4.1.rb
|
246
|
+
- lib/aipp/regions/LF/ENR-4.3.rb
|
247
|
+
- lib/aipp/regions/LF/ENR-5.1.rb
|
248
|
+
- lib/aipp/regions/LF/helper.rb
|
249
|
+
- lib/aipp/t_hash.rb
|
216
250
|
- lib/aipp/version.rb
|
217
251
|
- spec/lib/aipp/airac_spec.rb
|
218
252
|
- spec/lib/aipp/refinements_spec.rb
|
253
|
+
- spec/lib/aipp/t_hash_spec.rb
|
219
254
|
- spec/lib/aipp/version_spec.rb
|
220
255
|
- spec/sounds/failure.mp3
|
221
256
|
- spec/sounds/success.mp3
|
@@ -240,13 +275,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
240
275
|
version: '0'
|
241
276
|
requirements: []
|
242
277
|
rubyforge_project:
|
243
|
-
rubygems_version: 2.7.
|
278
|
+
rubygems_version: 2.7.6
|
244
279
|
signing_key:
|
245
280
|
specification_version: 4
|
246
281
|
summary: Parser for Aeronautical Information Publications (AIP).
|
247
282
|
test_files:
|
248
283
|
- spec/lib/aipp/airac_spec.rb
|
249
284
|
- spec/lib/aipp/refinements_spec.rb
|
285
|
+
- spec/lib/aipp/t_hash_spec.rb
|
250
286
|
- spec/lib/aipp/version_spec.rb
|
251
287
|
- spec/sounds/failure.mp3
|
252
288
|
- spec/sounds/success.mp3
|
data/lib/aipp/loader.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
module AIPP
|
2
|
-
class Loader
|
3
|
-
using AIPP::Refinements
|
4
|
-
|
5
|
-
attr_accessor :aixm
|
6
|
-
|
7
|
-
def self.parsers_path
|
8
|
-
Pathname(__dir__).join('parsers')
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.list
|
12
|
-
parsers_path.each_child.each.with_object({}) do |fir, hash|
|
13
|
-
hash[fir.basename.to_s] = fir.glob('*.rb').map do |aip|
|
14
|
-
aip.basename('.rb').to_s
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def initialize(fir:, aip:, airac:, limit:)
|
20
|
-
@fir, @aip, @airac, @limit = fir.upcase, aip.upcase, airac, limit
|
21
|
-
load_parser
|
22
|
-
@aixm = AIXM.document(effective_at: @airac)
|
23
|
-
convert!
|
24
|
-
warn "WARNING: document is not complete" unless aixm.complete?
|
25
|
-
warn aixm.errors.prepend("WARNING: document ist not valid:").join("\n") unless aixm.valid?
|
26
|
-
rescue LoadError
|
27
|
-
raise(LoadError, "no parser found for FIR `#{@fir}' and AIP `#{@aip}'")
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def load_parser
|
33
|
-
self.class.parsers_path.join(@fir, 'helpers').glob('*.rb').each do |helper|
|
34
|
-
require helper
|
35
|
-
end
|
36
|
-
require_relative "parsers/#{@fir}/#{@aip}"
|
37
|
-
self.singleton_class.send(:include, AIPP::Parsers)
|
38
|
-
end
|
39
|
-
|
40
|
-
def file
|
41
|
-
file_name = "#{@fir}_#{@aip}_#{@airac}.html"
|
42
|
-
Pathname.new(Dir.tmpdir).join(file_name).tap do |file_path|
|
43
|
-
IO.copy_stream(open(url), file_path) unless File.exist?(file_path)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def html
|
48
|
-
@html ||= Nokogiri::HTML5(file)
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
end
|
@@ -1,128 +0,0 @@
|
|
1
|
-
module AIPP
|
2
|
-
module Parsers
|
3
|
-
include Helpers::URL
|
4
|
-
include Helpers::HTML
|
5
|
-
using AIPP::Refinements
|
6
|
-
|
7
|
-
MASTER_MAP = {
|
8
|
-
'l' => 'ndb'
|
9
|
-
}.freeze
|
10
|
-
|
11
|
-
def convert!
|
12
|
-
cleanup!
|
13
|
-
html.css('tbody').each do |tbody|
|
14
|
-
name = last_id = nil
|
15
|
-
tbody.css('tr').to_enum.with_index(1).each do |tr, index|
|
16
|
-
break if index >= @limit
|
17
|
-
case tr.attr(:id)
|
18
|
-
when /TXT_NAME/
|
19
|
-
index -= 1
|
20
|
-
name = tr.css('td').text.strip.split("\n").first
|
21
|
-
when /GEO_LAT/
|
22
|
-
tds = tr.css('td')
|
23
|
-
type, runway = tds[0].text.strip.gsub(/\s+/, ' ').split(' ', 2)
|
24
|
-
master, slave = type.downcase.split('-')
|
25
|
-
if respond_to?("#{master}_from", true)
|
26
|
-
id = tds[1].text.strip.blank_to_nil || last_id
|
27
|
-
navaid = AIXM.send(
|
28
|
-
(MASTER_MAP[master] || master),
|
29
|
-
{ id: id, name: [name, runway].compact.join(' ') }.
|
30
|
-
merge(base_from(tds)).
|
31
|
-
merge(send("#{master}_from", tds))
|
32
|
-
)
|
33
|
-
navaid.schedule = schedule_from(tds[3])
|
34
|
-
navaid.remarks = remarks_from(tds[6], tds[7], tds[8])
|
35
|
-
navaid.send("associate_#{slave}", channel: channel_from(tds[2])) if slave
|
36
|
-
aixm.features << navaid
|
37
|
-
last_id = id
|
38
|
-
else
|
39
|
-
warn("WARNING: navigational aid `#{master}' at ##{index} skipped: not relevant to VFR")
|
40
|
-
end
|
41
|
-
end
|
42
|
-
rescue => exception
|
43
|
-
warn("WARNING: error parsing navigational aid at ##{index}: #{exception.message}", binding)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
true
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def base_from(tds)
|
52
|
-
{
|
53
|
-
xy: xy_from(tds[4]),
|
54
|
-
z: z_from(tds[5])
|
55
|
-
}
|
56
|
-
end
|
57
|
-
|
58
|
-
def vor_from(tds)
|
59
|
-
{
|
60
|
-
type: :conventional,
|
61
|
-
f: frequency_from(tds[2]),
|
62
|
-
north: :geographic,
|
63
|
-
}
|
64
|
-
end
|
65
|
-
|
66
|
-
def dme_from(tds)
|
67
|
-
{
|
68
|
-
channel: channel_from(tds[2])
|
69
|
-
}
|
70
|
-
end
|
71
|
-
|
72
|
-
def ndb_from(tds)
|
73
|
-
{
|
74
|
-
type: :en_route,
|
75
|
-
f: frequency_from(tds[2])
|
76
|
-
}
|
77
|
-
end
|
78
|
-
|
79
|
-
def l_from(tds)
|
80
|
-
{
|
81
|
-
type: :locator,
|
82
|
-
f: frequency_from(tds[2])
|
83
|
-
}
|
84
|
-
end
|
85
|
-
|
86
|
-
def tacan_from(tds)
|
87
|
-
{
|
88
|
-
channel: channel_from(tds[2])
|
89
|
-
}
|
90
|
-
end
|
91
|
-
|
92
|
-
def xy_from(td)
|
93
|
-
parts = td.text.strip.split(/\s+/)
|
94
|
-
AIXM.xy(lat: parts[0], long: parts[1])
|
95
|
-
end
|
96
|
-
|
97
|
-
def z_from(td)
|
98
|
-
parts = td.text.strip.split(/\s+/)
|
99
|
-
AIXM.z(parts[0].to_i, :qnh) if parts[1] == 'ft'
|
100
|
-
end
|
101
|
-
|
102
|
-
def frequency_from(td)
|
103
|
-
parts = td.text.strip.split(/\s+/)
|
104
|
-
AIXM.f(parts[0], parts[1]) if parts[1] =~ /hz$/i
|
105
|
-
end
|
106
|
-
|
107
|
-
def channel_from(td)
|
108
|
-
parts = td.text.strip.split(/\s+/)
|
109
|
-
parts.last if parts[-2].downcase == 'ch'
|
110
|
-
end
|
111
|
-
|
112
|
-
def schedule_from(td)
|
113
|
-
code = td.text.strip
|
114
|
-
AIXM.schedule(code: code) unless code.empty?
|
115
|
-
end
|
116
|
-
|
117
|
-
def remarks_from(*parts)
|
118
|
-
part_titles = ['COVERAGE', 'RDH (SLOPE)', 'LOCATION']
|
119
|
-
[].tap do |remarks|
|
120
|
-
parts.each.with_index do |part, index|
|
121
|
-
if part = part.text.gsub(/ +/, ' ').strip.blank_to_nil
|
122
|
-
remarks << "#{part_titles[index]}:\n#{part}"
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end.join("\n\n").blank_to_nil
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
@@ -1,105 +0,0 @@
|
|
1
|
-
module AIPP
|
2
|
-
module Parsers
|
3
|
-
include Helpers::URL
|
4
|
-
include Helpers::HTML
|
5
|
-
using AIPP::Refinements
|
6
|
-
|
7
|
-
def convert!
|
8
|
-
cleanup!
|
9
|
-
html.css('tbody').each do |tbody|
|
10
|
-
tbody.css('tr').to_enum.with_index(1).each do |tr, index|
|
11
|
-
break if index >= @limit
|
12
|
-
tds = tr.css('td')
|
13
|
-
master, slave = tds[1].text.strip.gsub(/[^\w-]/, '').downcase.split('-')
|
14
|
-
navaid = AIXM.send(master, base_from(tds).merge(send("#{master}_from", tds)))
|
15
|
-
navaid.schedule = schedule_from(tds[4])
|
16
|
-
navaid.remarks = remarks_from(tds[5], tds[7], tds[9])
|
17
|
-
navaid.send("associate_#{slave}", channel: channel_from(tds[3])) if slave
|
18
|
-
aixm.features << navaid
|
19
|
-
rescue => exception
|
20
|
-
warn("WARNING: error parsing navigational aid at ##{index}: #{exception.message}", binding)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
true
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def base_from(tds)
|
29
|
-
{
|
30
|
-
id: tds[2].text.strip,
|
31
|
-
name: tds[0].text.strip,
|
32
|
-
xy: xy_from(tds[5]),
|
33
|
-
z: z_from(tds[6])
|
34
|
-
}
|
35
|
-
end
|
36
|
-
|
37
|
-
def vor_from(tds)
|
38
|
-
{
|
39
|
-
type: :conventional,
|
40
|
-
f: frequency_from(tds[3]),
|
41
|
-
north: :geographic,
|
42
|
-
}
|
43
|
-
end
|
44
|
-
|
45
|
-
def dme_from(tds)
|
46
|
-
{
|
47
|
-
channel: channel_from(tds[3])
|
48
|
-
}
|
49
|
-
end
|
50
|
-
|
51
|
-
def ndb_from(tds)
|
52
|
-
{
|
53
|
-
type: :en_route,
|
54
|
-
f: frequency_from(tds[3])
|
55
|
-
}
|
56
|
-
end
|
57
|
-
|
58
|
-
def tacan_from(tds)
|
59
|
-
{
|
60
|
-
channel: channel_from(tds[3])
|
61
|
-
}
|
62
|
-
end
|
63
|
-
|
64
|
-
def xy_from(td)
|
65
|
-
parts = td.text.strip.split(/\s+/)
|
66
|
-
AIXM.xy(lat: parts[0], long: parts[1])
|
67
|
-
end
|
68
|
-
|
69
|
-
def z_from(td)
|
70
|
-
parts = td.text.strip.split(/\s+/)
|
71
|
-
AIXM.z(parts[0].to_i, :qnh) if parts[1] == 'ft'
|
72
|
-
end
|
73
|
-
|
74
|
-
def frequency_from(td)
|
75
|
-
parts = td.text.strip.split(/\s+/)
|
76
|
-
AIXM.f(parts[0], parts[1]) if parts[1] =~ /hz$/i
|
77
|
-
end
|
78
|
-
|
79
|
-
def channel_from(td)
|
80
|
-
parts = td.text.strip.split(/\s+/)
|
81
|
-
parts.last if parts[-2].downcase == 'ch'
|
82
|
-
end
|
83
|
-
|
84
|
-
def schedule_from(td)
|
85
|
-
code = td.text.strip
|
86
|
-
AIXM.schedule(code: code) unless code.empty?
|
87
|
-
end
|
88
|
-
|
89
|
-
def remarks_from(*parts)
|
90
|
-
part_titles = ['RANGE', 'SITUATION', 'OBSERVATIONS']
|
91
|
-
[].tap do |remarks|
|
92
|
-
parts.each.with_index do |part, index|
|
93
|
-
text = if index == 0
|
94
|
-
part = part.text.strip.split(/\s+/)
|
95
|
-
part.shift(2)
|
96
|
-
part.join(' ').blank_to_nil
|
97
|
-
else
|
98
|
-
part.text.strip.blank_to_nil
|
99
|
-
end
|
100
|
-
remarks << "#{part_titles[index]}:\n#{text}" if text
|
101
|
-
end
|
102
|
-
end.join("\n\n").blank_to_nil
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|