aipp 0.2.5 → 0.2.6

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 (63) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG.md +8 -0
  5. data/README.md +40 -14
  6. data/exe/aip2aixm +1 -1
  7. data/exe/aip2ofmx +1 -1
  8. data/lib/aipp.rb +2 -0
  9. data/lib/aipp/aip.rb +17 -12
  10. data/lib/aipp/downloader.rb +1 -1
  11. data/lib/aipp/executable.rb +15 -12
  12. data/lib/aipp/parser.rb +58 -43
  13. data/lib/aipp/pdf.rb +1 -1
  14. data/lib/aipp/regions/LF/AD-1.3.rb +7 -6
  15. data/lib/aipp/regions/LF/AD-1.6.rb +7 -5
  16. data/lib/aipp/regions/LF/AD-2.rb +16 -9
  17. data/lib/aipp/regions/LF/AD-3.1.rb +6 -6
  18. data/lib/aipp/regions/LF/ENR-2.1.rb +81 -6
  19. data/lib/aipp/regions/LF/ENR-4.1.rb +3 -1
  20. data/lib/aipp/regions/LF/ENR-4.3.rb +2 -3
  21. data/lib/aipp/regions/LF/ENR-5.1.rb +15 -2
  22. data/lib/aipp/regions/LF/ENR-5.4.rb +90 -0
  23. data/lib/aipp/regions/LF/ENR-5.5.rb +12 -10
  24. data/lib/aipp/regions/LF/fixtures/AD-1.3.yml +2 -2
  25. data/lib/aipp/regions/LF/helpers/base.rb +17 -9
  26. data/lib/aipp/regions/LF/helpers/radio_AD.rb +21 -13
  27. data/lib/aipp/t_hash.rb +3 -3
  28. data/lib/aipp/version.rb +1 -1
  29. data/lib/core_ext/enumerable.rb +7 -7
  30. data/lib/core_ext/string.rb +9 -4
  31. metadata +156 -168
  32. metadata.gz.sig +1 -0
  33. data/.github/workflows/test.yml +0 -26
  34. data/.gitignore +0 -8
  35. data/.ruby-version +0 -1
  36. data/.yardopts +0 -3
  37. data/Guardfile +0 -7
  38. data/TODO.md +0 -6
  39. data/aipp.gemspec +0 -45
  40. data/gems.rb +0 -3
  41. data/rakefile.rb +0 -12
  42. data/spec/fixtures/border.geojson +0 -201
  43. data/spec/fixtures/document.pdf +0 -0
  44. data/spec/fixtures/document.pdf.json +0 -1
  45. data/spec/fixtures/new.html +0 -6
  46. data/spec/fixtures/new.pdf +0 -0
  47. data/spec/fixtures/new.txt +0 -1
  48. data/spec/fixtures/source.zip +0 -0
  49. data/spec/lib/aipp/airac_spec.rb +0 -98
  50. data/spec/lib/aipp/border_spec.rb +0 -135
  51. data/spec/lib/aipp/downloader_spec.rb +0 -81
  52. data/spec/lib/aipp/patcher_spec.rb +0 -46
  53. data/spec/lib/aipp/pdf_spec.rb +0 -124
  54. data/spec/lib/aipp/t_hash_spec.rb +0 -44
  55. data/spec/lib/aipp/version_spec.rb +0 -7
  56. data/spec/lib/core_ext/enumberable_spec.rb +0 -76
  57. data/spec/lib/core_ext/hash_spec.rb +0 -27
  58. data/spec/lib/core_ext/integer_spec.rb +0 -15
  59. data/spec/lib/core_ext/nil_class_spec.rb +0 -11
  60. data/spec/lib/core_ext/string_spec.rb +0 -112
  61. data/spec/sounds/failure.mp3 +0 -0
  62. data/spec/sounds/success.mp3 +0 -0
  63. data/spec/spec_helper.rb +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cddca26d9635de7aa2ded8bde0def36adf97d548e9c133358443f7812c778ef6
4
- data.tar.gz: cadd71e6709c70f03a6f2ceda4af1ef38b049d70f3aaad2cd45ef3fc792df192
3
+ metadata.gz: 11e3df230b0b8dcafdef31e97ed97e2bbf7d6c45f75cb86949ee92a3980e07f4
4
+ data.tar.gz: 9fe425721151ec0c99677813ac283de61f274f97a6d103cbce8d4d178e8f794d
5
5
  SHA512:
6
- metadata.gz: 5d511918c12c5c877c64cb4d5f28e5d968cdd98e08f9dfc72b8f188579da214aa63e953b36a5f17dbdd8b2d5d0281209f29d2693a458c4b7613d0d012c4111e7
7
- data.tar.gz: b3b4a1dc343049c3aec1c58290e52d09fb43adb476a6c085271d31f0d20c016db19cb9ed0f4355e8eb78f199fa3e6b9580a2f2a30d2e6ff8bcc6548f818d8e08
6
+ metadata.gz: 000f611816b7d7b7112649830b3cd1ae383fd9b2a6defcc554715bfbabb9c3008c1f90f3f8062d3c43630c06f7642cd8e8f3c559a99e6bb7ccc4e045062333b5
7
+ data.tar.gz: c29e73e68318fe197e06d07a08c79fd5cfcb6be9aff3c5fbb96150f0385682e5a51284caf311026b8623d342a77b73485db1509a844de3217161656b52e8818c
Binary file
Binary file
@@ -1,3 +1,11 @@
1
+ ## 0.2.6
2
+
3
+ #### Additions
4
+ * Detect duplicate features
5
+
6
+ #### Changes
7
+ * Require Ruby 2.7
8
+
1
9
  ## 0.2.5
2
10
 
3
11
  #### Additions
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  [![Version](https://img.shields.io/gem/v/aipp.svg?style=flat)](https://rubygems.org/gems/aipp)
2
- [![Tests](https://github.com/svoop/aipp/workflows/Test/badge.svg)](https://github.com/svoop/aipp/actions?workflow=Test)
2
+ [![Tests](https://img.shields.io/github/workflow/status/svoop/aipp/Test.svg?style=flat&label=tests)](https://github.com/svoop/aipp/actions?workflow=Test)
3
3
  [![Donorbox](https://img.shields.io/badge/donate-on_donorbox-yellow.svg)](https://donorbox.org/bitcetera)
4
4
 
5
5
  # AIPP
@@ -25,12 +25,36 @@ This gem incluces two executables to download and parse aeronautical data as HTM
25
25
 
26
26
  ## Install
27
27
 
28
- Add this to your <tt>Gemfile</tt> or <tt>gems.rb</tt>:
28
+ ### Security
29
+
30
+ This gem is [cryptographically signed](https://guides.rubygems.org/security/#using-gems) in order to assure it hasn't been tampered with. Unless already done, please add the author's public key as a trusted certificate now:
31
+
32
+ ```
33
+ gem cert --add <(curl -Ls https://raw.github.com/svoop/aipp/master/certs/svoop.pem)
34
+ ```
35
+
36
+ ### Standalone
37
+
38
+ Make sure to have the [latest version of Ruby](https://www.ruby-lang.org/en/documentation/installation/) and then install this gem:
39
+
40
+ ```
41
+ gem install aipp --trust-policy MediumSecurity
42
+ ```
43
+
44
+ ### Bundler
45
+
46
+ If you're familiar with [Bundler](https://bundler.io) powered Ruby projects, you might prefer to add the following to your <tt>Gemfile</tt> or <tt>gems.rb</tt>:
29
47
 
30
48
  ```ruby
31
49
  gem aipp
32
50
  ```
33
51
 
52
+ And then install the bundle:
53
+
54
+ ```
55
+ bundle install --trust-policy MediumSecurity
56
+ ```
57
+
34
58
  ## Usage
35
59
 
36
60
  See the built-in help for all options:
@@ -61,23 +85,23 @@ You'll find a directory for each region which contains the following items:
61
85
  * `manifest.csv` – diffable manifest (see below)
62
86
  * `config.yml`<br>This file contains configuration which will be read on subsequent runs, most notably the namespace UUID used to identify the creator of OFMX files.
63
87
 
64
- The manifest is a CSV which lists every feature on a separate line along with its hashes and comment. You can `diff` or `git diff` two manifests:
88
+ The manifest is a CSV which lists every feature on a separate line along with its hashes, AIP and comment. You can `diff` or `git diff` two manifests:
65
89
 
66
90
  ```diff
67
91
  $ git diff -U0 2019-09-12/manifest.csv 2019-10-10/manifest.csv
68
92
 
69
93
  --- a/2019-09-12/manifest.csv
70
94
  +++ b/2019-10-10/manifest.csv
71
- @@ -89,0 +90 @@ Aha,449f4791,d6d4bff8,Address: PHONE for LFF958FC61
72
- +Aha,44b9a044,cf55a3cf,Address: PHONE for LF49929DD6
73
- @@ -134 +135 @@ Aha,6acfbcc5,c4f57e3f,Address: FAX for LF897E1A6F
74
- -Aha,6b381b32,fb947716,Address: RADIO for LFPO
75
- +Aha,6b381b32,b9723b7e,Address: RADIO for LFPO
76
- @@ -253,0 +255 @@ Aha,d01c4282,7cc8db7f,Address: PHONE for LF0C413AE2
77
- +Aha,d05cfbff,74fb76bc,Address: FAX for LF49929DD6
78
- @@ -327 +329 @@ Ahp,068f4f01,1dc2fb5c,Airport: LFEA BELLE ILE
79
- -Ahp,06d04910,e18af958,Airport: LFFDE9077D TONNERRE CENTRE HOSPITALIER
80
- +Ahp,06d04910,cc522711,Airport: LFFDE9077D TONNERRE CENTRE HOSPITALIER
95
+ @@ -204 +204 @@ AD-1.3,Ahp,9e9f031e,d6f22057,Airport: LFLJ COURCHEVEL
96
+ -AD-1.3,Ahp,9f1eed18,37ddbbde,Airport: LFQD ARRAS ROCLINCOURT
97
+ +AD-1.3,Ahp,9f1eed18,f0e60105,Airport: LFQD ARRAS ROCLINCOURT
98
+ @@ -312 +312 @@ AD-2,Aha,4250c9ee,04d49dc7,Address: RADIO for LFHV
99
+ -AD-2,Aha,6b381b32,fb947716,Address: RADIO for LFPO
100
+ +AD-2,Aha,6b381b32,b9723b7e,Address: RADIO for LFPO
101
+ @@ -664 +663,0 @@ AD-2,Ser,3920a7fd,4545c5eb,Service: AFIS by LFGA TWR
102
+ -AD-2,Ser,39215774,1f13f2cf,Service: APP by LFCR APP
103
+ @@ -878 +876,0 @@ AD-2,Ser,bb5228d7,7cfb4572,Service: TWR by LFMH TWR
104
+ -AD-2,Ser,bc72caf2,0a15b39c,Service: FIS by LFCR FIC
81
105
  (...)
82
106
  ```
83
107
 
@@ -135,7 +159,9 @@ Inside the `parse` method, you have access to the following methods:
135
159
 
136
160
  * [`read`](https://www.rubydoc.info/gems/aipp/AIPP/AIP#read-instance_method) – download and read an AIP file
137
161
  * [`add`](https://www.rubydoc.info/gems/aipp/AIPP/AIP#add-instance_method) – add a [`AIXM::Feature`](https://www.rubydoc.info/gems/aixm/AIXM/Feature)
138
- * [`select`](https://www.rubydoc.info/gems/aipp/AIPP/AIP#find-instance_method) – search previously written [`AIXM::Feature`s](https://www.rubydoc.info/gems/aixm/AIXM/Feature)
162
+ * [`find`](https://www.rubydoc.info/gems/aipp/AIPP/AIP#find-instance_method) – find previously written [`AIXM::Feature`s](https://www.rubydoc.info/gems/aixm/AIXM/Feature) by object
163
+ * [`find_by`](https://www.rubydoc.info/gems/aipp/AIPP/AIP#find_by-instance_method) – find previously written [`AIXM::Feature`s](https://www.rubydoc.info/gems/aixm/AIXM/Feature) by class and attribute values
164
+ * [`unique`](https://www.rubydoc.info/gems/aipp/AIPP/AIP#unique-instance_method) – prevent duplicate [`AIXM::Feature`s](https://www.rubydoc.info/gems/aixm/AIXM/Feature)
139
165
  * some core extensions from ActiveSupport – [`Object#blank`](https://www.rubydoc.info/gems/activesupport/Object#blank%3F-instance_method) and [`String`](https://www.rubydoc.info/gems/activesupport/String)
140
166
  * core extensions from this gem – [`Object`](https://www.rubydoc.info/gems/aipp/Object), [`NilClass`](https://www.rubydoc.info/gems/aipp/NilClass), [`Integer`](https://www.rubydoc.info/gems/aipp/Integer), [`String`](https://www.rubydoc.info/gems/aipp/String), [`Hash`](https://www.rubydoc.info/gems/aipp/Hash) and [`Enumerable`](https://www.rubydoc.info/gems/aipp/Enumerable)
141
167
 
@@ -4,7 +4,7 @@ require 'bundler/inline'
4
4
 
5
5
  gemfile do
6
6
  source 'https://rubygems.org'
7
- ruby '>= 2.5'
7
+ ruby '>= 2.7'
8
8
  gem 'aipp', '~> 0'
9
9
  end
10
10
 
@@ -4,7 +4,7 @@ require 'bundler/inline'
4
4
 
5
5
  gemfile do
6
6
  source 'https://rubygems.org'
7
- ruby '>= 2.5'
7
+ ruby '>= 2.7'
8
8
  gem 'aipp', '~> 0'
9
9
  end
10
10
 
@@ -41,6 +41,8 @@ require_relative 'aipp/parser'
41
41
  require_relative 'aipp/downloader'
42
42
 
43
43
  # Disable "did you mean?" suggestions
44
+ #
45
+ # @!visibility private
44
46
  module DidYouMean::Correctable
45
47
  remove_method :to_s
46
48
  end
@@ -52,24 +52,29 @@ module AIPP
52
52
  # Add feature to AIXM
53
53
  #
54
54
  # @param feature [AIXM::Feature] e.g. airport or airspace
55
+ # @return [AIXM::Feature] added feature
55
56
  def add(feature)
56
57
  verbose_info "Adding #{feature.inspect}"
57
- aixm.features << feature
58
+ aixm.add_feature feature
59
+ feature
58
60
  end
59
61
 
60
- # Search features previously written to AIXM and return those matching the
61
- # given class and attribute values
62
+ # @!method find_by(klass, attributes={})
63
+ # Find objects of the given class and optionally with the given attribute
64
+ # values previously written to AIXM.
62
65
  #
63
- # @example
64
- # select(:airport, id: "LFNT")
66
+ # @note This method is delegated to +AIXM::Association::Array+.
67
+ # @see https://www.rubydoc.info/gems/aixm/AIXM/Association/Array#find_by-instance_method
65
68
  #
66
- # @param klass [Class, Symbol] feature class like AIXM::Feature::Airport or
67
- # AIXM::Feature::NavigationalAid::VOR, shorthand notations as symbols
68
- # e.g. :airport or :vor as listed in AIXM::CLASSES are recognized as well
69
- # @param attributes [Hash] filter by these attributes and their values
70
- # @return [Array<AIXM::Feature>]
71
- def select(*args)
72
- aixm.select_features(*args)
69
+ # @!method find(object)
70
+ # Find equal objects previously written to AIXM.
71
+ #
72
+ # @note This method is delegated to +AIXM::Association::Array+.
73
+ # @see https://www.rubydoc.info/gems/aixm/AIXM/Association/Array#find-instance_method
74
+ %i(find_by find).each do |method|
75
+ define_method method do |*args|
76
+ aixm.features.send(method, *args)
77
+ end
73
78
  end
74
79
  end
75
80
 
@@ -58,7 +58,7 @@ module AIPP
58
58
  file = work_path.join([document, type].join('.'))
59
59
  unless file.exist?
60
60
  verbose_info "Downloading #{document}"
61
- IO.copy_stream(Kernel.open(url), file)
61
+ IO.copy_stream(URI.open(url), file)
62
62
  end
63
63
  convert file
64
64
  end
@@ -15,15 +15,18 @@ module AIPP
15
15
  Download online AIP and convert it to #{options[:schema].upcase}.
16
16
  Usage: #{File.basename($0)} [options]
17
17
  END
18
- o.on('-d', '--airac DATE', String, %Q[AIRAC date (default: "#{@options[:airac].date.xmlschema}")]) { |v| @options[:airac] = AIPP::AIRAC.new(v) }
19
- o.on('-r', '--region STRING', String, 'region (e.g. "LF")') { |v| @options[:region] = v.upcase }
20
- o.on('-a', '--aip STRING', String, 'process this AIP only (e.g. "ENR-5.1")') { |v| @options[:aip] = v.upcase }
21
- o.on('-m', '--[no-]mid', 'insert mid attributes into all Uid elements (default: false)') { |v| @options[:mid] = v }
22
- o.on('-s', '--storage DIR', String, 'storage directory (default: "~/.aipp")') { |v| @options[:storage] = Pathname(v) }
23
- o.on('-f', '--[no-]force', 'ignore XML schema validation (default: false)') { |v| @options[:force] = v }
24
- o.on('-v', '--[no-]verbose', 'verbose output (default: false)') { |v| $VERBOSE_INFO = v }
25
- o.on('-w', '--pry-on-warn [ID]', Integer, 'open pry on warn with ID (default: nil)') { |v| $PRY_ON_WARN = v || true }
26
- o.on('-e', '--[no-]pry-on-error', 'open pry on error (default: false)') { |v| $PRY_ON_ERROR = v }
18
+ o.on('-d', '--airac DATE', String, %Q[AIRAC date (default: "#{@options[:airac].date.xmlschema}")]) { @options[:airac] = AIPP::AIRAC.new(_1) }
19
+ o.on('-r', '--region STRING', String, 'region (e.g. "LF")') { @options[:region] = _1.upcase }
20
+ o.on('-a', '--aip STRING', String, 'process this AIP only (e.g. "ENR-5.1")') { @options[:aip] = _1.upcase }
21
+ if options[:schema] == :ofmx
22
+ o.on('-g', '--[no-]grouped-obstacles', 'group obstacles (time-consuming!)') { @options[:grouped_obstacles] = _1 }
23
+ o.on('-m', '--[no-]mid', 'insert mid attributes into all Uid elements (default: false)') { @options[:mid] = _1 }
24
+ end
25
+ o.on('-s', '--storage DIR', String, 'storage directory (default: "~/.aipp")') { @options[:storage] = Pathname(_1) }
26
+ o.on('-f', '--[no-]force', 'ignore XML schema validation (default: false)') { @options[:force] = _1 }
27
+ o.on('-v', '--[no-]verbose', 'verbose output (default: false)') { $VERBOSE_INFO = _1 }
28
+ o.on('-w', '--pry-on-warn [ID]', Integer, 'open pry on warn with ID (default: nil)') { $PRY_ON_WARN = _1 || true }
29
+ o.on('-e', '--[no-]pry-on-error', 'open pry on error (default: false)') { $PRY_ON_ERROR = _1 }
27
30
  o.on('-A', '--about', 'show author/license information and exit') { about }
28
31
  o.on('-R', '--readme', 'show README and exit') { readme }
29
32
  o.on('-L', '--list', 'list implemented regions and AIPs') { list }
@@ -42,12 +45,12 @@ module AIPP
42
45
  parser.read_region
43
46
  parser.parse_aip
44
47
  parser.validate_aixm
45
- parser.write_aixm
46
48
  parser.write_build
49
+ parser.write_aixm
47
50
  parser.write_config
48
51
  end
49
52
  rescue => error
50
- puts "ERROR: #{error.message}"
53
+ puts "ERROR: #{error.message}".magenta
51
54
  Pry::rescued(error) if $PRY_ON_ERROR
52
55
  end
53
56
  end
@@ -69,7 +72,7 @@ module AIPP
69
72
  regions_path = Pathname($0).dirname.join('..', 'gems', "aipp-#{AIPP::VERSION}", 'lib', 'aipp', 'regions')
70
73
  hash = Dir.each_child(regions_path).each.with_object({}) do |region, hash|
71
74
  hash[region] = Dir.children(regions_path.join(region)).sort.map do |aip|
72
- File.basename(aip, '.rb') unless aip == 'helper.rb'
75
+ File.basename(aip, '.rb') if File.file?(regions_path.join(region, aip))
73
76
  end.compact
74
77
  end
75
78
  puts hash.to_yaml.sub(/\A\W*/, '')
@@ -28,12 +28,13 @@ module AIPP
28
28
  @options[:storage] = options[:storage].join(options[:region])
29
29
  @options[:storage].mkpath
30
30
  @config = {}
31
- @aixm = AIXM.document(region: @options[:region], effective_at: @options[:airac].date)
31
+ @aixm = AIXM.document(effective_at: @options[:airac].date)
32
32
  @dependencies = THash.new
33
33
  @fixtures = {}
34
34
  @borders = {}
35
35
  @cache = OpenStruct.new
36
36
  AIXM.send("#{options[:schema]}!")
37
+ AIXM.config.region = options[:region]
37
38
  end
38
39
 
39
40
  # Read the configuration from config.yml.
@@ -89,12 +90,22 @@ module AIPP
89
90
  ).attach_patches.tap(&:parse).detach_patches
90
91
  end
91
92
  end
93
+ if options[:grouped_obstacles]
94
+ info("Grouping obstacles")
95
+ aixm.group_obstacles!
96
+ end
97
+ info("Counting #{aixm.features.count} features")
92
98
  end
93
99
 
94
100
  # Validate the AIXM document.
95
101
  #
96
102
  # @raise [RuntimeError] if the document is not valid
97
103
  def validate_aixm
104
+ info("Detecting duplicates")
105
+ if (duplicates = aixm.features.duplicates).any?
106
+ message = "duplicates found:\n" + duplicates.map { "#{_1.inspect} from #{_1.source}" }.join("\n")
107
+ @options[:force] ? warn(message, pry: binding) : fail(message)
108
+ end
98
109
  info("Validating #{options[:schema].upcase}")
99
110
  unless aixm.valid?
100
111
  message = "invalid #{options[:schema].upcase} document:\n" + aixm.errors.map(&:message).join("\n")
@@ -102,56 +113,60 @@ module AIPP
102
113
  end
103
114
  end
104
115
 
105
- # Write the AIXM document.
106
- def write_aixm
107
- info("Writing #{aixm_file}")
108
- AIXM.config.mid_region = options[:region] if options[:mid]
109
- File.write(aixm_file, aixm.to_xml)
110
- end
111
-
112
116
  # Write the AIXM document and context information.
113
117
  def write_build
114
- info("Writing build")
115
- builds_path.mkpath
116
- build_file = builds_path.join("#{@options[:airac].date.xmlschema}.zip")
117
- build_file.delete if build_file.exist?
118
- Dir.mktmpdir do |tmp_dir|
119
- tmp_dir = Pathname(tmp_dir)
120
- AIXM.config.mid_region = options[:region]
121
- # AIXM/OFMX file
122
- File.write(tmp_dir.join(aixm_file), aixm.to_xml)
123
- # Build details
124
- File.write(
125
- tmp_dir.join('build.yaml'), {
126
- version: AIPP::VERSION,
127
- config: @config,
128
- options: @options
129
- }.to_yaml
130
- )
131
- # Manifest
132
- manifest, buffer, feature, uid, comment = [], '', '', '', ''
133
- File.open(tmp_dir.join(aixm_file)).each do |line|
134
- buffer << line
135
- case line
136
- when /^ {2}<(\w{3}) / then buffer, feature = line, $1
137
- when /^ {4}<#{feature}Uid mid="(.*?)"/ then uid = $1
138
- when /^ {2}<!-- (.*) -->/ then comment = $1
139
- when /^ {2}<\/#{feature}>/
140
- manifest << [feature, uid[0,8], buffer.payload_hash(region: options[:region])[0,8], comment].to_csv
141
- feature, uid = '', ''
118
+ if @options[:aip]
119
+ info ("Skipping build")
120
+ else
121
+ info("Writing build")
122
+ builds_path.mkpath
123
+ build_file = builds_path.join("#{@options[:airac].date.xmlschema}.zip")
124
+ Dir.mktmpdir do |tmp_dir|
125
+ tmp_dir = Pathname(tmp_dir)
126
+ # AIXM/OFMX file
127
+ AIXM.config.mid = true
128
+ File.write(tmp_dir.join(aixm_file), aixm.to_xml)
129
+ # Build details
130
+ File.write(
131
+ tmp_dir.join('build.yaml'), {
132
+ version: AIPP::VERSION,
133
+ config: @config,
134
+ options: @options
135
+ }.to_yaml
136
+ )
137
+ # Manifest
138
+ manifest, buffer, feature, aip, uid, comment = [], '', '', '', '', ''
139
+ File.open(tmp_dir.join(aixm_file)).each do |line|
140
+ buffer << line
141
+ case line
142
+ when /^ {2}<(\w{3}).*source=".*?\|.*?\|(.*?)\|/ then buffer, feature, aip = line, $1, $2
143
+ when /^ {4}<#{feature}Uid[^>]+?mid="(.*?)"/ then uid = $1
144
+ when /^ {2}<!-- (.*) -->/ then comment = $1
145
+ when /^ {2}<\/#{feature}>/
146
+ manifest << [aip, feature, uid[0,8], AIXM::PayloadHash.new(buffer).to_uuid[0,8], comment].to_csv
147
+ feature, aip, uid = '', '', ''
148
+ end
142
149
  end
143
- end
144
- manifest = manifest.sort.prepend "Feature,Short Uid Hash,Short Feature Hash,Comment\n"
145
- File.write(tmp_dir.join('manifest.csv'), manifest.join)
146
- # Zip it
147
- Zip::File.open(build_file, Zip::File::CREATE) do |zip|
148
- tmp_dir.children.each do |entry|
149
- zip.add(entry.basename.to_s, entry) unless entry.basename.to_s[0] == '.'
150
+ manifest = manifest.sort.prepend "AIP,Feature,Short Uid Hash,Short Feature Hash,Comment\n"
151
+ File.write(tmp_dir.join('manifest.csv'), manifest.join)
152
+ # Zip it
153
+ build_file.delete if build_file.exist?
154
+ Zip::File.open(build_file, Zip::File::CREATE) do |zip|
155
+ tmp_dir.children.each do |entry|
156
+ zip.add(entry.basename.to_s, entry) unless entry.basename.to_s[0] == '.'
157
+ end
150
158
  end
151
159
  end
152
160
  end
153
161
  end
154
162
 
163
+ # Write the AIXM document.
164
+ def write_aixm
165
+ info("Writing #{aixm_file}")
166
+ AIXM.config.mid = options[:mid]
167
+ File.write(aixm_file, aixm.to_xml)
168
+ end
169
+
155
170
  # Write the configuration to config.yml.
156
171
  def write_config
157
172
  info("Writing config.yml")
@@ -117,7 +117,7 @@ module AIPP
117
117
  end
118
118
 
119
119
  def page_for(index:)
120
- @page_ranges.index(@page_ranges.bsearch { |i| i >= index }) + 1
120
+ @page_ranges.index(@page_ranges.bsearch { _1 >= index }) + 1
121
121
  end
122
122
  end
123
123
  end
@@ -42,7 +42,7 @@ module AIPP
42
42
  @airport = airport_from tr
43
43
  verbose_info "Parsing #{@airport.id}"
44
44
  ad2_exists = false
45
- if airport = select(:airport, id: @airport.id).first
45
+ if airport = find_by(:airport, id: @airport.id).first
46
46
  ad2_exists = true
47
47
  @airport = airport
48
48
  end
@@ -81,7 +81,7 @@ module AIPP
81
81
  when /ouv.+cap|milit/ then :permitted
82
82
  when /usa.+restr|priv/ then :reservation_required
83
83
  end
84
- @airport.add_usage_limitation(limitation) do |l|
84
+ @airport.add_usage_limitation(type: limitation) do |l|
85
85
  (%w(s ns p) & raw_conditions).each do |raw_purpose|
86
86
  l.add_condition do |c|
87
87
  c.realm = raw_limitation.match?(/milit/) ? :military : :civilian
@@ -111,6 +111,7 @@ module AIPP
111
111
  name: tds[0].text.strip.split.join('/')
112
112
  ).tap do |runway|
113
113
  @runway = runway # TODO: needed for now for surface composition patches to work
114
+ bidirectional = runway.name.include? '/'
114
115
  runway.length = AIXM.d(tds[1].css('span[id$="VAL_LEN"]').text.to_i, :m)
115
116
  runway.width = AIXM.d(tds[1].css('span[id$="VAL_WID"]').text.to_i, :m)
116
117
  unless (text = tds[1].css('span[id*="SURFACE"]').text.compact).blank?
@@ -122,16 +123,16 @@ module AIPP
122
123
  runway.remarks = tds[7].text.cleanup.blank_to_nil
123
124
  values = tds[2].text.remove('°').strip.split
124
125
  runway.forth.geographic_orientation = AIXM.a(values.first.to_i)
125
- runway.back.geographic_orientation = AIXM.a(values.last.to_i)
126
+ runway.back.geographic_orientation = AIXM.a(values.last.to_i) if bidirectional
126
127
  parts = tds[3].text.strip.split(/\n\s+\n\s+/, 2)
127
128
  runway.forth.xy = (xy_from(parts[0]) unless parts[0].blank?)
128
- runway.back.xy = (xy_from(parts[1]) unless parts[1].blank?)
129
+ runway.back.xy = (xy_from(parts[1]) unless parts[1].blank?) if bidirectional
129
130
  values = tds[4].text.strip.split
130
131
  runway.forth.z = AIXM.z(values.first.to_i, :qnh)
131
- runway.back.z = AIXM.z(values.last.to_i, :qnh)
132
+ runway.back.z = AIXM.z(values.last.to_i, :qnh) if bidirectional
132
133
  displaced_thresholds = displaced_thresholds_from(tds[5])
133
134
  runway.forth.displaced_threshold = displaced_thresholds.first
134
- runway.back.displaced_threshold = displaced_thresholds.last
135
+ runway.back.displaced_threshold = displaced_thresholds.last if bidirectional
135
136
  end
136
137
  end
137
138