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.
@@ -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.1.3
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-01-29 00:00:00.000000000 Z
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.3
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.3
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: '1'
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: '1'
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/loader.rb
209
- - lib/aipp/parsers/LF/AD-1.5.rb
210
- - lib/aipp/parsers/LF/ENR-4.1.rb
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.3
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
@@ -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