aipp 0.2.6 → 1.0.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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +21 -0
  4. data/README.md +147 -91
  5. data/exe/aip2aixm +2 -2
  6. data/exe/aip2ofmx +2 -2
  7. data/lib/aipp/aip.rb +96 -11
  8. data/lib/aipp/border.rb +77 -46
  9. data/lib/aipp/debugger.rb +101 -0
  10. data/lib/aipp/downloader.rb +18 -5
  11. data/lib/aipp/executable.rb +33 -20
  12. data/lib/aipp/parser.rb +42 -37
  13. data/lib/aipp/patcher.rb +5 -2
  14. data/lib/aipp/regions/LF/README.md +49 -0
  15. data/lib/aipp/regions/LF/aerodromes.rb +223 -0
  16. data/lib/aipp/regions/LF/d_p_r_airspaces.rb +56 -0
  17. data/lib/aipp/regions/LF/dangerous_activities.rb +49 -0
  18. data/lib/aipp/regions/LF/designated_points.rb +47 -0
  19. data/lib/aipp/regions/LF/fixtures/aerodromes.yml +608 -0
  20. data/lib/aipp/regions/LF/helipads.rb +122 -0
  21. data/lib/aipp/regions/LF/helpers/base.rb +167 -174
  22. data/lib/aipp/regions/LF/helpers/surface.rb +49 -0
  23. data/lib/aipp/regions/LF/helpers/usage_limitation.rb +20 -0
  24. data/lib/aipp/regions/LF/navigational_aids.rb +85 -0
  25. data/lib/aipp/regions/LF/obstacles.rb +153 -0
  26. data/lib/aipp/regions/LF/serviced_airspaces.rb +70 -0
  27. data/lib/aipp/regions/LF/services.rb +172 -0
  28. data/lib/aipp/t_hash.rb +3 -4
  29. data/lib/aipp/version.rb +1 -1
  30. data/lib/aipp.rb +7 -5
  31. data/lib/core_ext/enumerable.rb +2 -2
  32. data/lib/core_ext/hash.rb +21 -5
  33. data/lib/core_ext/nokogiri.rb +54 -0
  34. data/lib/core_ext/string.rb +32 -65
  35. data.tar.gz.sig +0 -0
  36. metadata +70 -81
  37. metadata.gz.sig +0 -0
  38. data/lib/aipp/airac.rb +0 -55
  39. data/lib/aipp/regions/LF/AD-1.3.rb +0 -177
  40. data/lib/aipp/regions/LF/AD-1.6.rb +0 -33
  41. data/lib/aipp/regions/LF/AD-2.rb +0 -344
  42. data/lib/aipp/regions/LF/AD-3.1.rb +0 -185
  43. data/lib/aipp/regions/LF/ENR-2.1.rb +0 -167
  44. data/lib/aipp/regions/LF/ENR-4.1.rb +0 -41
  45. data/lib/aipp/regions/LF/ENR-4.3.rb +0 -27
  46. data/lib/aipp/regions/LF/ENR-5.1.rb +0 -106
  47. data/lib/aipp/regions/LF/ENR-5.4.rb +0 -90
  48. data/lib/aipp/regions/LF/ENR-5.5.rb +0 -55
  49. data/lib/aipp/regions/LF/fixtures/AD-1.3.yml +0 -511
  50. data/lib/aipp/regions/LF/fixtures/AD-2.yml +0 -185
  51. data/lib/aipp/regions/LF/fixtures/AD-3.1.yml +0 -10
  52. data/lib/aipp/regions/LF/helpers/URL.rb +0 -26
  53. data/lib/aipp/regions/LF/helpers/navigational_aid.rb +0 -104
  54. data/lib/aipp/regions/LF/helpers/radio_AD.rb +0 -110
  55. data/lib/core_ext/object.rb +0 -43
@@ -1,26 +0,0 @@
1
- module AIPP
2
- module LF
3
- module Helpers
4
- module URL
5
-
6
- # @param aip_file [String] e.g. ENR-5.1, AD-2.LFMV or VAC-LFMV
7
- def url_for(aip_file)
8
- case aip_file
9
- when /^VAC\-(\w+)/
10
- "https://www.sia.aviation-civile.gouv.fr/dvd/eAIP_%s/Atlas-VAC/PDF_AIPparSSection/VAC/AD/AD-2.%s.pdf" % [
11
- options[:airac].date.strftime('%d_%^b_%Y'), # 04_JAN_2018
12
- $1
13
- ]
14
- else
15
- "https://www.sia.aviation-civile.gouv.fr/dvd/eAIP_%s/FRANCE/AIRAC-%s/html/eAIP/FR-%s-fr-FR.html" % [
16
- options[:airac].date.strftime('%d_%^b_%Y'), # 04_JAN_2018
17
- options[:airac].date.xmlschema, # 2018-01-04
18
- aip_file
19
- ]
20
- end
21
- end
22
-
23
- end
24
- end
25
- end
26
- end
@@ -1,104 +0,0 @@
1
- module AIPP
2
- module LF
3
- module Helpers
4
- module NavigationalAid
5
-
6
- def navigational_aid_from(tds, source:, sections:)
7
- NavigationalAid.new(tds, source: source, sections: sections).build
8
- end
9
-
10
- class NavigationalAid
11
- include AIPP::LF::Helpers::Base
12
-
13
- # Map atypical navigational aid denominations
14
- NAVIGATIONAL_AIDS = {
15
- 'vor' => 'vor',
16
- 'dme' => 'dme',
17
- 'ndb' => 'ndb',
18
- 'tacan' => 'tacan',
19
- 'l' => 'ndb' # L denominates a NDB of class locator
20
- }.freeze
21
-
22
- def initialize(tds, source:, sections:)
23
- @tds, @source, @sections = tds, source, sections
24
- end
25
-
26
- def build
27
- master, slave = @tds[:type].text.strip.gsub(/[^\w-]/, '').downcase.split('-')
28
- master = NAVIGATIONAL_AIDS.fetch(master, master)
29
- slave = NAVIGATIONAL_AIDS.fetch(slave, slave)
30
- return nil unless NAVIGATIONAL_AIDS.keys.include? master
31
- AIXM.send(master, common.merge(send(master))).tap do |navigational_aid|
32
- navigational_aid.source = @source
33
- navigational_aid.remarks = remarks
34
- navigational_aid.timetable = timetable_from!(@tds[:schedule].text)
35
- navigational_aid.send("associate_#{slave}", channel: channel_from(@tds[:f].text)) if slave
36
- end
37
- end
38
-
39
- private
40
-
41
- def common
42
- {
43
- organisation: organisation_lf,
44
- id: @tds[:id].text.strip,
45
- name: @tds[:name].text.strip,
46
- xy: xy_from(@tds[:xy].text),
47
- z: z_from(@tds[:z].text)
48
- }
49
- end
50
-
51
- def vor
52
- {
53
- type: :conventional,
54
- f: f_from(@tds[:f].text),
55
- north: :magnetic,
56
- }
57
- end
58
-
59
- def dme
60
- {
61
- channel: channel_from(@tds[:f].text)
62
- }
63
- end
64
-
65
- def ndb
66
- {
67
- type: @tds[:type].text.strip == 'L' ? :locator : :en_route,
68
- f: f_from(@tds[:f].text)
69
- }
70
- end
71
-
72
- def tacan
73
- {
74
- channel: channel_from(@tds[:f].text)
75
- }
76
- end
77
-
78
- def remarks
79
- @sections.map do |section, td|
80
- if text = td.text.strip.blank_to_nil
81
- "**#{section.upcase}**\n#{text}"
82
- end
83
- end.compact.join("\n\n").blank_to_nil
84
- end
85
-
86
- def z_from(text)
87
- parts = text.strip.split(/\s+/)
88
- AIXM.z(parts[0].to_i, :qnh) if parts[1] == 'ft'
89
- end
90
-
91
- def f_from(text)
92
- parts = text.strip.split(/\s+/)
93
- AIXM.f(parts[0].to_f, parts[1]) if parts[1] =~ /hz$/i
94
- end
95
-
96
- def channel_from(text)
97
- parts = text.strip.split(/\s+/)
98
- parts.last if parts[-2].downcase == 'ch'
99
- end
100
- end
101
- end
102
- end
103
- end
104
- end
@@ -1,110 +0,0 @@
1
- module AIPP
2
- module LF
3
- module Helpers
4
- module RadioAD
5
-
6
- # Service types to be ignored
7
- IGNORED_TYPES = %w(D-ATIS).freeze
8
-
9
- # Service types to be encoded as addresses
10
- ADDRESS_TYPES = %w(A/A A/G).freeze
11
-
12
- # Unknown service types to be encoded as units
13
- SERVICE_TYPES = {
14
- 'CEV' => { type: :other, remarks: "CEV (centre d'essais en vol / flight test center)" },
15
- 'SRE' => { type: :other, remarks: "SRE (elément radar de surveillance du PAR / surveillance radar element of PAR)" }
16
- }.freeze
17
-
18
- def addresses_from(trs)
19
- return [] if trs.text.blank?
20
- trs.map do |tr|
21
- tds = tr.css('td')
22
- type = tds[0].text.strip
23
- next if IGNORED_TYPES.include? type
24
- f, callsign, _, remarks = parts_from(tds).values
25
- callsign = callsign.split(/\n\s*/).join('/')
26
- if ADDRESS_TYPES.include?(type)
27
- AIXM.address(
28
- source: source(position: tr.line),
29
- type: :radio_frequency,
30
- address: f.freq.to_s
31
- ).tap do |address|
32
- address.remarks = ["#{type} - indicatif/callsign #{callsign}", remarks.blank_to_nil].compact.join("\n")
33
- end
34
- end
35
- end.compact
36
- end
37
-
38
- def units_from(trs, airport:)
39
- return [] if trs.text.blank?
40
- trs.each_with_object({}) do |tr, services|
41
- tds = tr.css('td')
42
- type = tds[0].text.strip
43
- next if IGNORED_TYPES.include?(type) || ADDRESS_TYPES.include?(type)
44
- f, callsigns, timetable, remarks = parts_from(tds).values
45
- callsigns = if callsigns.match?(/\(\w{2}\)/)
46
- callsigns.cleanup.split("\n").each_with_object({}) do |callsign, hash|
47
- callsign =~ /^(.*)\s+\((\w{2})\)/
48
- hash[$2.downcase.to_sym] = $1
49
- end
50
- else
51
- { fr: callsigns }
52
- end
53
- if SERVICE_TYPES.include? type
54
- type = SERVICE_TYPES.dig(type, :type)
55
- remarks = [SERVICE_TYPES.dig(type, :remarks), remarks.blank_to_nil].compact.join("\n")
56
- end
57
- unless services.include? type
58
- @source = source(position: tr.line) # TODO
59
- services[type] = AIXM.service(
60
- # TODO: add source as soon as it is supported by components
61
- # source: source(position: tr.line),
62
- type: type
63
- )
64
- end
65
- code = $1 if timetable.sub!(/(#{AIXM::H_RE})\b/, '')
66
- services[type].add_frequency(
67
- AIXM.frequency(
68
- transmission_f: f,
69
- callsigns: callsigns
70
- ).tap do |frequency|
71
- frequency.type = :standard
72
- frequency.type = :alternative if remarks.sub!(%r{fréquence supplétive/auxiliary frequency\S*}i, '')
73
- frequency.timetable = AIXM.timetable(code: code) if code
74
- frequency.remarks = [remarks, timetable.blank_to_nil].compact.join("\n").cleanup.blank_to_nil
75
- end
76
- )
77
- end.values.each_with_object(AIXM::Association::Array.new) do |service, units|
78
- type = service.guessed_unit_type
79
- unit = units.find_by(:unit, name: airport.id, type: type).first
80
- unless unit
81
- unit = AIXM.unit(
82
- source: @source, # TODO
83
- organisation: organisation_lf, # TODO: not yet implemented
84
- type: type,
85
- name: airport.id,
86
- class: :icao # TODO: verify whether all units are ICAO
87
- ).tap do |unit|
88
- unit.airport = airport
89
- end
90
- units.send(:push, unit)
91
- end
92
- unit.add_service(service)
93
- end
94
- end
95
-
96
- private
97
-
98
- def parts_from(tds)
99
- {
100
- f: AIXM.f(tds[2].css('span').first.text.to_f, tds[2].css('span').last.text),
101
- callsign: tds[1].text.strip,
102
- timetable: tds[3].text.strip,
103
- remarks: tds[4].text.strip.sub(/Canal (8.33|25)/i, '') # TEMP: ignore canal spacing warnings
104
- }
105
- end
106
-
107
- end
108
- end
109
- end
110
- end
@@ -1,43 +0,0 @@
1
- class Object
2
-
3
- # Issue a warning and maybe open a Pry session attached to the error or
4
- # binding passed.
5
- #
6
- # @example with error context
7
- # begin
8
- # (...)
9
- # rescue => error
10
- # warn("oops", pry: error)
11
- # end
12
- # @example with binding context
13
- # warn("oops", pry: binding)
14
- #
15
- # @param message [String] warning message
16
- # @param pry [Exception, Binding, nil] attach the Pry session to this error
17
- # or binding
18
- def warn(message, pry: nil)
19
- $WARN_COUNTER = $WARN_COUNTER.to_i + 1
20
- Kernel.warn "WARNING #{$WARN_COUNTER}: #{message}".red
21
- if $PRY_ON_WARN == true || $PRY_ON_WARN == $WARN_COUNTER
22
- case pry
23
- when Exception then Pry::rescued(pry)
24
- when Binding then pry.pry
25
- end
26
- end
27
- end
28
-
29
- # Issue an informational message.
30
- #
31
- # @param message [String] informational message
32
- def info(message, color: :black)
33
- puts message.send(color)
34
- end
35
-
36
- # Issue a verbose informational message.
37
- #
38
- # @param message [String] verbose informational message
39
- def verbose_info(message, color: :blue)
40
- info(message, color: color) if $VERBOSE_INFO
41
- end
42
-
43
- end