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
@@ -32,60 +32,13 @@ class String
32
32
  # are preserved and not collapsed into one space.
33
33
  #
34
34
  # @example
35
- # " foo\n\nbar \r".copact # => "foo\nbar"
35
+ # " foo\n\nbar \r".compact # => "foo\nbar"
36
36
  #
37
37
  # @return [String] compacted string
38
38
  def compact
39
39
  split("\n").map { _1.squish.blank_to_nil }.compact.join("\n")
40
40
  end
41
41
 
42
- # Calculate the correlation of two strings by counting mutual words
43
- #
44
- # Both strings are normalized as follows:
45
- # * remove accents, umlauts etc
46
- # * remove everything but members of the +\w+ class
47
- # * downcase
48
- #
49
- # The normalized strings are split into words. Only words fulfilling either
50
- # of the following conditions are taken into consideration:
51
- # * words present in and translated by the +synonyms+ map
52
- # * words of at least 5 characters length
53
- # * words consisting of exactly one letter followed by any number of digits
54
- # (an optional whitespace between the two is ignored, e.g. "D 25" is the
55
- # same as "D25")
56
- #
57
- # The +synonyms+ map is an array where terms in even positions map to their
58
- # synonym in the following (odd) position:
59
- #
60
- # SYNONYMS = ['term1', 'synonym1', 'term2', 'synonym2']
61
- #
62
- # @example
63
- # subject = "Truck en route on N 3 sud"
64
- # subject.correlate("my car is on D25") # => 0
65
- # subject.correlate("my truck is on D25") # => 1
66
- # subject.correlate("my truck is on N3") # => 2
67
- # subject.correlate("south", ['sud', 'south']) # => 1
68
- #
69
- # @param other [String] string to compare with
70
- # @param synonyms [Array<String>] array of synonym pairs
71
- # @return [Integer] 0 for unrelated strings and positive integers for related
72
- # strings with higher numbers indicating tighter correlation
73
- def correlate(other, synonyms=[])
74
- self_words, other_words = [self, other].map do |string|
75
- string.
76
- unicode_normalize(:nfd).
77
- downcase.gsub(/[-\u2013]/, ' ').
78
- remove(/[^\w\s]/).
79
- gsub(/\b(\w)\s?(\d+)\b/, '\1\2').
80
- compact.
81
- split(/\W+/).
82
- map { (i = synonyms.index(_1)).nil? ? _1 : (i.odd? ? _1 : synonyms[i + 1]).upcase }.
83
- keep_if { _1.match?(/\w{5,}|\w\d+|[[:upper:]]/) }.
84
- uniq
85
- end
86
- (self_words & other_words).count
87
- end
88
-
89
42
  # Similar to +strip+, but remove any leading or trailing non-letters/numbers
90
43
  # which includes whitespace
91
44
  def full_strip
@@ -97,6 +50,37 @@ class String
97
50
  scan(pattern).tap { remove! pattern }
98
51
  end
99
52
 
53
+ # Apply the patterns in the given order and return...
54
+ # * first capture group - if a pattern matches and contains a capture group
55
+ # * entire match - if a pattern matches and contains no capture group
56
+ # * +default+ - if no pattern matches and a +default+ is set
57
+ # * +nil+ - if no pattern matches and no +default+ is set
58
+ #
59
+ # @example
60
+ # "A/A: 123.5 mhz".first_match(/123\.5/) # => "123.5"
61
+ # "A/A: 123.5 mhz".first_match(/:\s+([\d.]+)/) # => "123.5"
62
+ # "A/A: 123.5 mhz".first_match(/121\.5/) # nil
63
+ # "A/A: 123.5 mhz".first_match(/(121\.5)/) # nil
64
+ # "A/A: 123.5 mhz".first_match(/121\.5/, default: "123") # "123"
65
+ #
66
+ # @param patterns [Array<Regexp>] one or more patterns to apply in order
67
+ # @param default [String] string to return instead of +nil+ if the pattern
68
+ # doesn't match
69
+ # @return [String, nil]
70
+ def first_match(*patterns, default: nil)
71
+ patterns.each do |pattern|
72
+ if captures = match(pattern)
73
+ return captures[1] || captures[0]
74
+ end
75
+ end
76
+ default
77
+ end
78
+
79
+ # Remove all XML/HTML tags and entities from the string
80
+ def strip_markup
81
+ self.gsub(/<.*?>|&[#\da-z]+;/i, '')
82
+ end
83
+
100
84
  # Same as +to_f+ but accept both dot and comma as decimal separator
101
85
  #
102
86
  # @example
@@ -109,21 +93,4 @@ class String
109
93
  sub(/,/, '.').to_f
110
94
  end
111
95
 
112
- # Add spaces between obviously glued words:
113
- # * camel glued words
114
- # * three-or-more-letter and number-only words
115
- #
116
- # @example
117
- # "thisString has spaceProblems".unglue # => "this String has space problems"
118
- # "the first123meters of D25".unglue # => "the first 123 meters of D25"
119
- #
120
- # @return [String] unglued string
121
- def unglue
122
- self.dup.tap do |string|
123
- [/([[:lower:]])([[:upper:]])/, /([[:alpha:]]{3,})(\d)/, /(\d)([[:alpha:]]{3,})/].freeze.each do |regexp|
124
- string.gsub!(regexp, '\1 \2')
125
- end
126
- end
127
- end
128
-
129
96
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,95 +1,101 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aipp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sven Schwyn
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
13
  MIIDcDCCAligAwIBAgIBATANBgkqhkiG9w0BAQUFADA/MQ0wCwYDVQQDDARydWJ5
14
14
  MRkwFwYKCZImiZPyLGQBGRYJYml0Y2V0ZXJhMRMwEQYKCZImiZPyLGQBGRYDY29t
15
- MB4XDTIwMDMxNDE5NDgwNVoXDTIxMDMxNDE5NDgwNVowPzENMAsGA1UEAwwEcnVi
15
+ MB4XDTIxMTEwODE0MzIyM1oXDTIyMTEwODE0MzIyM1owPzENMAsGA1UEAwwEcnVi
16
16
  eTEZMBcGCgmSJomT8ixkARkWCWJpdGNldGVyYTETMBEGCgmSJomT8ixkARkWA2Nv
17
- bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL4k2DCa8/eAFiak4Kwe
18
- 0Iu8dk0JfHWeywjVVSNv6PtnQ96B/1jLmw5Wb+xYJSyvG6KEOzEMWA/lqO+nIrdO
19
- 2LDRxuWojH5GROp/dtQ+SxsWlvui4cs9iBmI5Mj0mc1UgST3UFf60ry8OnyR+E9N
20
- RVVZZykAGmxwyAqD1aq5Yt0lZMdvrGnaLWcZdKC99e812pdTN948k8Iw2GJAaNtH
21
- Tp17XDfDNBANHjYy9xCqrxvNTfT4Bs43rPA1A77+mkPgI2Vx51u2CWA+K3hP4gAZ
22
- F50xqnagzgXSOzCme1mC/sUUmoAAB39g2CuNocWuhv0R3/HeqdwAsA/1XpDF2NfQ
23
- zW8CAwEAAaN3MHUwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFDfY
24
- gRWUI+J6nX7Po7Zq0zvDopfYMB0GA1UdEQQWMBSBEnJ1YnlAYml0Y2V0ZXJhLmNv
17
+ bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANwuD4geNdhpSVNJTtHb
18
+ fmVAoPxmER4oyGgaVJSidn/OjU5PcpdypMI/WIxfvjfFizq6kQYAsJZbCr6fG+UN
19
+ 2dZGMXcAC/uKQL5nYESjCPJ4IJP/SC+fiiEpxHQk7PNFoiUVRUieUZIAfHZAdnY3
20
+ ye1/niW7ud0vwKIMrysKWxjgkE0Y6Af1QLzV/6brVRRC5MvHIzYJd8BiSP+wY1O8
21
+ VElw1f6d90KEz2vaQfX7vCxrzIbvAnYiSvM0AIPy/zigTqpW6w3w4sQxQj81oQ9U
22
+ 9vDYtQzXj0c9VrSLvb0DgiGug2cU2bDjA4L3cBE1szX4tbfo8syYqMq51/kTGDxW
23
+ YNUCAwEAAaN3MHUwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFJ8r
24
+ wy1HraZDqg3Khf9UonMWMtJUMB0GA1UdEQQWMBSBEnJ1YnlAYml0Y2V0ZXJhLmNv
25
25
  bTAdBgNVHRIEFjAUgRJydWJ5QGJpdGNldGVyYS5jb20wDQYJKoZIhvcNAQEFBQAD
26
- ggEBAFsTSBbxIkTdppL8yFl0KglyUMq9DjkMwvz7ORJzHMfw1S2OmXMYnJ5fSXFu
27
- C/9puwYMdD6V3THyqc1Rhj6RRZ/576MDwIXMgOETQfPTT6jNE+p4cRougDrQ32aV
28
- 29WIAY21/o0FBuJZqxLDRTu6O7AHrjFnv7Kkpr1oYiR9G4MNEihyNt909nHnSixC
29
- qn5dLDjawWVvAz5oeD1sE0Kyp6CDY8i3NfBu4aqz8uAbaEJh3jpY5NW2Lv++s7hf
30
- EUqN8dad5Oosf9hYbfFXPzkJIIGiKMS4e1cbnAr/vadELoccfEN9tSlLuW/voNqA
31
- 2635TmaVXxUEgIOzRhGlE1+frXI=
26
+ ggEBACI7lJKRbnRjz0T4Wb9jH4SE0A2yaHAoBzj96luVDjNyoRT3688trEZS75Sg
27
+ GKfChxqKncBrSpxJ0YfWbymNHfUrKhcdSifJ/TtUrTasm6LSnJYLOnLKDO3v8eL3
28
+ gRTq8a5wA7Xtijx3MJEyzdeUh7N+UMKuPps/flPgH5yabUxgxrvuhrXF7Z96nrsP
29
+ EOmNMTc8H7wo4BAKfuMcI/Gh2oCf+tAhr0bGsXyBikmJ6XA45mrOMgv19M1+aMpn
30
+ 1+2Y1+i+4jd1B7qxIgOLxQTNIJiwE0sqU1itFfuesfgUACS7M0IV9u9Bp4hBGNEw
31
+ 5JcY2h7owdMxXIvgk1oakgldFJc=
32
32
  -----END CERTIFICATE-----
33
- date: 2020-03-15 00:00:00.000000000 Z
33
+ date: 2022-03-05 00:00:00.000000000 Z
34
34
  dependencies:
35
35
  - !ruby/object:Gem::Dependency
36
- name: aixm
36
+ name: airac
37
37
  requirement: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - ">="
39
+ - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: 0.3.10
41
+ version: '1.0'
42
42
  type: :runtime
43
43
  prerelease: false
44
44
  version_requirements: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - ">="
46
+ - - "~>"
47
47
  - !ruby/object:Gem::Version
48
- version: 0.3.10
48
+ version: '1.0'
49
49
  - !ruby/object:Gem::Dependency
50
- name: activesupport
50
+ name: aixm
51
51
  requirement: !ruby/object:Gem::Requirement
52
52
  requirements:
53
53
  - - "~>"
54
54
  - !ruby/object:Gem::Version
55
- version: '5'
55
+ version: '1.1'
56
56
  type: :runtime
57
57
  prerelease: false
58
58
  version_requirements: !ruby/object:Gem::Requirement
59
59
  requirements:
60
60
  - - "~>"
61
61
  - !ruby/object:Gem::Version
62
- version: '5'
62
+ version: '1.1'
63
63
  - !ruby/object:Gem::Dependency
64
- name: nokogiri
64
+ name: activesupport
65
65
  requirement: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - "~>"
68
68
  - !ruby/object:Gem::Version
69
- version: '1'
69
+ version: '7'
70
70
  type: :runtime
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
73
73
  requirements:
74
74
  - - "~>"
75
75
  - !ruby/object:Gem::Version
76
- version: '1'
76
+ version: '7'
77
77
  - !ruby/object:Gem::Dependency
78
- name: nokogumbo
78
+ name: nokogiri
79
79
  requirement: !ruby/object:Gem::Requirement
80
80
  requirements:
81
81
  - - "~>"
82
82
  - !ruby/object:Gem::Version
83
- version: '2'
83
+ version: '1'
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 1.12.0
84
87
  type: :runtime
85
88
  prerelease: false
86
89
  version_requirements: !ruby/object:Gem::Requirement
87
90
  requirements:
88
91
  - - "~>"
89
92
  - !ruby/object:Gem::Version
90
- version: '2'
93
+ version: '1'
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 1.12.0
91
97
  - !ruby/object:Gem::Dependency
92
- name: pdf-reader
98
+ name: roo
93
99
  requirement: !ruby/object:Gem::Requirement
94
100
  requirements:
95
101
  - - "~>"
@@ -103,7 +109,7 @@ dependencies:
103
109
  - !ruby/object:Gem::Version
104
110
  version: '2'
105
111
  - !ruby/object:Gem::Dependency
106
- name: json
112
+ name: pdf-reader
107
113
  requirement: !ruby/object:Gem::Requirement
108
114
  requirements:
109
115
  - - "~>"
@@ -117,7 +123,7 @@ dependencies:
117
123
  - !ruby/object:Gem::Version
118
124
  version: '2'
119
125
  - !ruby/object:Gem::Dependency
120
- name: rubyzip
126
+ name: json
121
127
  requirement: !ruby/object:Gem::Requirement
122
128
  requirements:
123
129
  - - "~>"
@@ -131,21 +137,21 @@ dependencies:
131
137
  - !ruby/object:Gem::Version
132
138
  version: '2'
133
139
  - !ruby/object:Gem::Dependency
134
- name: colorize
140
+ name: rubyzip
135
141
  requirement: !ruby/object:Gem::Requirement
136
142
  requirements:
137
143
  - - "~>"
138
144
  - !ruby/object:Gem::Version
139
- version: '0'
145
+ version: '2'
140
146
  type: :runtime
141
147
  prerelease: false
142
148
  version_requirements: !ruby/object:Gem::Requirement
143
149
  requirements:
144
150
  - - "~>"
145
151
  - !ruby/object:Gem::Version
146
- version: '0'
152
+ version: '2'
147
153
  - !ruby/object:Gem::Dependency
148
- name: pry
154
+ name: colorize
149
155
  requirement: !ruby/object:Gem::Requirement
150
156
  requirements:
151
157
  - - "~>"
@@ -159,33 +165,19 @@ dependencies:
159
165
  - !ruby/object:Gem::Version
160
166
  version: '0'
161
167
  - !ruby/object:Gem::Dependency
162
- name: pry-rescue
168
+ name: debug
163
169
  requirement: !ruby/object:Gem::Requirement
164
170
  requirements:
165
- - - "~>"
166
- - !ruby/object:Gem::Version
167
- version: '1'
168
- type: :runtime
169
- prerelease: false
170
- version_requirements: !ruby/object:Gem::Requirement
171
- requirements:
172
- - - "~>"
173
- - !ruby/object:Gem::Version
174
- version: '1'
175
- - !ruby/object:Gem::Dependency
176
- name: pry-stack_explorer
177
- requirement: !ruby/object:Gem::Requirement
178
- requirements:
179
- - - "~>"
171
+ - - ">="
180
172
  - !ruby/object:Gem::Version
181
- version: '0'
173
+ version: 1.0.0
182
174
  type: :runtime
183
175
  prerelease: false
184
176
  version_requirements: !ruby/object:Gem::Requirement
185
177
  requirements:
186
- - - "~>"
178
+ - - ">="
187
179
  - !ruby/object:Gem::Version
188
- version: '0'
180
+ version: 1.0.0
189
181
  - !ruby/object:Gem::Dependency
190
182
  name: rake
191
183
  requirement: !ruby/object:Gem::Requirement
@@ -334,52 +326,49 @@ files:
334
326
  - exe/aip2ofmx
335
327
  - lib/aipp.rb
336
328
  - lib/aipp/aip.rb
337
- - lib/aipp/airac.rb
338
329
  - lib/aipp/border.rb
330
+ - lib/aipp/debugger.rb
339
331
  - lib/aipp/downloader.rb
340
332
  - lib/aipp/executable.rb
341
333
  - lib/aipp/parser.rb
342
334
  - lib/aipp/patcher.rb
343
335
  - lib/aipp/pdf.rb
344
- - lib/aipp/regions/LF/AD-1.3.rb
345
- - lib/aipp/regions/LF/AD-1.6.rb
346
- - lib/aipp/regions/LF/AD-2.rb
347
- - lib/aipp/regions/LF/AD-3.1.rb
348
- - lib/aipp/regions/LF/ENR-2.1.rb
349
- - lib/aipp/regions/LF/ENR-4.1.rb
350
- - lib/aipp/regions/LF/ENR-4.3.rb
351
- - lib/aipp/regions/LF/ENR-5.1.rb
352
- - lib/aipp/regions/LF/ENR-5.4.rb
353
- - lib/aipp/regions/LF/ENR-5.5.rb
336
+ - lib/aipp/regions/LF/README.md
337
+ - lib/aipp/regions/LF/aerodromes.rb
354
338
  - lib/aipp/regions/LF/borders/france_atlantic_coast.geojson
355
339
  - lib/aipp/regions/LF/borders/france_atlantic_territorial_sea.geojson
356
340
  - lib/aipp/regions/LF/borders/france_ecrins_national_park.geojson
357
341
  - lib/aipp/regions/LF/borders/france_mediterranean_coast.geojson
358
- - lib/aipp/regions/LF/fixtures/AD-1.3.yml
359
- - lib/aipp/regions/LF/fixtures/AD-2.yml
360
- - lib/aipp/regions/LF/fixtures/AD-3.1.yml
361
- - lib/aipp/regions/LF/helpers/URL.rb
342
+ - lib/aipp/regions/LF/d_p_r_airspaces.rb
343
+ - lib/aipp/regions/LF/dangerous_activities.rb
344
+ - lib/aipp/regions/LF/designated_points.rb
345
+ - lib/aipp/regions/LF/fixtures/aerodromes.yml
346
+ - lib/aipp/regions/LF/helipads.rb
362
347
  - lib/aipp/regions/LF/helpers/base.rb
363
- - lib/aipp/regions/LF/helpers/navigational_aid.rb
364
- - lib/aipp/regions/LF/helpers/radio_AD.rb
348
+ - lib/aipp/regions/LF/helpers/surface.rb
349
+ - lib/aipp/regions/LF/helpers/usage_limitation.rb
350
+ - lib/aipp/regions/LF/navigational_aids.rb
351
+ - lib/aipp/regions/LF/obstacles.rb
352
+ - lib/aipp/regions/LF/serviced_airspaces.rb
353
+ - lib/aipp/regions/LF/services.rb
365
354
  - lib/aipp/t_hash.rb
366
355
  - lib/aipp/version.rb
367
356
  - lib/core_ext/enumerable.rb
368
357
  - lib/core_ext/hash.rb
369
358
  - lib/core_ext/integer.rb
370
359
  - lib/core_ext/nil_class.rb
371
- - lib/core_ext/object.rb
360
+ - lib/core_ext/nokogiri.rb
372
361
  - lib/core_ext/string.rb
373
362
  homepage: https://github.com/svoop/aipp
374
363
  licenses:
375
364
  - MIT
376
365
  metadata:
377
366
  homepage_uri: https://github.com/svoop/aipp
378
- changelog_uri: https://github.com/svoop/aipp/blob/master/CHANGELOG.md
367
+ changelog_uri: https://github.com/svoop/aipp/blob/main/CHANGELOG.md
379
368
  source_code_uri: https://github.com/svoop/aipp
380
369
  documentation_uri: https://www.rubydoc.info/gems/aipp
381
370
  bug_tracker_uri: https://github.com/svoop/aipp/issues
382
- post_install_message:
371
+ post_install_message:
383
372
  rdoc_options:
384
373
  - "--title"
385
374
  - AIP Parser and Converter
@@ -394,15 +383,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
394
383
  requirements:
395
384
  - - ">="
396
385
  - !ruby/object:Gem::Version
397
- version: 2.7.0
386
+ version: 3.0.0
398
387
  required_rubygems_version: !ruby/object:Gem::Requirement
399
388
  requirements:
400
389
  - - ">="
401
390
  - !ruby/object:Gem::Version
402
391
  version: '0'
403
392
  requirements: []
404
- rubygems_version: 3.1.2
405
- signing_key:
393
+ rubygems_version: 3.3.8
394
+ signing_key:
406
395
  specification_version: 4
407
396
  summary: Parser for aeronautical information publications
408
397
  test_files: []
metadata.gz.sig CHANGED
Binary file
data/lib/aipp/airac.rb DELETED
@@ -1,55 +0,0 @@
1
- module AIPP
2
-
3
- # AIRAC cycle date calculations
4
- #
5
- # @example
6
- # airac = AIPP::AIRAC.new('2018-01-01')
7
- # airac.date # => #<Date: 2017-12-07 ((2458095j,0s,0n),+0s,2299161j)>
8
- # airac.id # => 1713
9
- # airac.next_date # => #<Date: 2018-01-04 ((2458123j,0s,0n),+0s,2299161j)>
10
- # airac.next_id # => 1801
11
- class AIRAC
12
- # First AIRAC date following the last cycle length modification
13
- ROOT_DATE = Date.parse('2015-06-25').freeze
14
-
15
- # Length of one AIRAC cycle
16
- DAYS_PER_CYCLE = 28
17
-
18
- # @return [Date] AIRAC effective on date
19
- attr_reader :date
20
-
21
- # @return [Integer] AIRAC cycle ID
22
- attr_reader :id
23
-
24
- # @param any_date [Date] any date within the AIRAC cycle (default: today)
25
- def initialize(any_date = nil)
26
- any_date = any_date ? Date.parse(any_date.to_s) : Date.today
27
- fail(ArgumentError, "cannot calculate dates before #{ROOT_DATE}") if any_date < ROOT_DATE
28
- @date = date_for(any_date)
29
- @id = id_for(@date)
30
- end
31
-
32
- # @return [Date] next AIRAC effective on date
33
- def next_date
34
- date + DAYS_PER_CYCLE
35
- end
36
-
37
- # @return [Integer] next AIRAC cycle ID
38
- def next_id
39
- id_for next_date
40
- end
41
-
42
- private
43
-
44
- # Find the AIRAC date for +any_date+
45
- def date_for(any_date)
46
- ROOT_DATE + (any_date - ROOT_DATE).to_i / DAYS_PER_CYCLE * DAYS_PER_CYCLE
47
- end
48
-
49
- # Find the AIRAC ID for the AIRAC +date+
50
- def id_for(date)
51
- (date.year % 100) * 100 + ((date.yday - 1) / 28) + 1
52
- end
53
-
54
- end
55
- end
@@ -1,177 +0,0 @@
1
- module AIPP
2
- module LF
3
-
4
- # Aerodromes
5
- class AD13 < AIP
6
-
7
- include AIPP::LF::Helpers::Base
8
-
9
- DEPENDS = %w(AD-2)
10
-
11
- # Map names of id-less airports to unofficial ids
12
- ID_LESS_AIRPORTS = {
13
- "ALBE" => 'LF9001',
14
- "BEAUMONT DE LOMAGNE" => 'LF9002',
15
- "BERDOUES" => 'LF9003',
16
- "BOULOC" => 'LF9004',
17
- "BUXEUIL ST REMY / CREUSE" => 'LF9005',
18
- "CALVIAC" => 'LF9006',
19
- "CAYLUS" => 'LF9007',
20
- "CORBONOD" => 'LF9008',
21
- "L'ISLE EN DODON" => 'LF9009',
22
- "LACAVE LE FRAU" => 'LF9010',
23
- "LUCON CHASNAIS" => 'LF9011',
24
- "PEYRELEVADE" => 'LF9012',
25
- "SAINT CYR LA CAMPAGNE" => 'LF9013',
26
- "SEPTFONDS" => 'LF9014',
27
- "TALMONT VENDEE AIR PARK" => 'LF9015'
28
- }.freeze
29
-
30
- PURPOSES = {
31
- "s" => :scheduled,
32
- "ns" => :not_scheduled,
33
- "p" => :private
34
- }.freeze
35
-
36
- def parse
37
- ad2_exists = false
38
- tbody = prepare(html: read).css('tbody').first # skip altiports
39
- tbody.css('tr').to_enum.with_index(1).each do |tr, index|
40
- if tr.attr(:id).match?(/-TXT_NAME-/)
41
- add @airport if @airport && !ad2_exists
42
- @airport = airport_from tr
43
- verbose_info "Parsing #{@airport.id}"
44
- ad2_exists = false
45
- if airport = find_by(:airport, id: @airport.id).first
46
- ad2_exists = true
47
- @airport = airport
48
- end
49
- add_usage_limitations_from tr
50
- next
51
- end
52
- @airport.add_runway(runway_from(tr)) unless ad2_exists
53
- rescue => error
54
- warn("error parsing #{@airport.id} at ##{index}: #{error.message}", pry: error)
55
- end
56
- add @airport if @airport && !ad2_exists
57
- end
58
-
59
- private
60
-
61
- def airport_from(tr)
62
- tds = tr.css('td')
63
- id = tds[0].text.strip.blank_to_nil || ID_LESS_AIRPORTS.fetch(tds[1].text.strip)
64
- AIXM.airport(
65
- source: source(position: tr.line),
66
- organisation: organisation_lf, # TODO: not yet implemented
67
- id: id,
68
- name: tds[1].text.strip,
69
- xy: xy_from(tds[3].text)
70
- ).tap do |airport|
71
- airport.z = AIXM.z(tds[4].text.strip.to_i, :qnh)
72
- airport.declination = tds[2].text.remove('°').strip.to_f
73
- # airport.transition_z = AIXM.z(5000, :qnh) # TODO: default - exceptions exist
74
- end
75
- end
76
-
77
- def add_usage_limitations_from(tr)
78
- raw_limitation = tr.css('td:nth-of-type(8)').text.cleanup.downcase
79
- raw_conditions = tr.css('td:nth-of-type(6)').text.cleanup.downcase.split(%r([\s/]+))
80
- limitation = case raw_limitation
81
- when /ouv.+cap|milit/ then :permitted
82
- when /usa.+restr|priv/ then :reservation_required
83
- end
84
- @airport.add_usage_limitation(type: limitation) do |l|
85
- (%w(s ns p) & raw_conditions).each do |raw_purpose|
86
- l.add_condition do |c|
87
- c.realm = raw_limitation.match?(/milit/) ? :military : :civilian
88
- if (%w(intl ntl) - raw_conditions).empty?
89
- c.origin = :any
90
- else
91
- c.origin = :national if raw_conditions.include?('ntl')
92
- c.origin = :international if raw_conditions.include?('intl')
93
- end
94
- if (%w(ifr vfr) - raw_conditions).empty?
95
- c.rule = :ifr_and_vfr
96
- else
97
- c.rule = :ifr if raw_conditions.include?('ifr')
98
- c.rule = :vfr if raw_conditions.include?('vfr')
99
- end
100
- c.purpose = PURPOSES[raw_purpose]
101
- end
102
- end
103
- l.remarks = "Usage restreint (voir VAC) / restricted use (see VAC)" if raw_limitation.match?(/usa.+restr/)
104
- l.remarks = "Propriété privée / privately owned" if raw_limitation.match?(/priv/)
105
- end
106
- end
107
-
108
- def runway_from(tr)
109
- tds = tr.css('td')
110
- AIXM.runway(
111
- name: tds[0].text.strip.split.join('/')
112
- ).tap do |runway|
113
- @runway = runway # TODO: needed for now for surface composition patches to work
114
- bidirectional = runway.name.include? '/'
115
- runway.length = AIXM.d(tds[1].css('span[id$="VAL_LEN"]').text.to_i, :m)
116
- runway.width = AIXM.d(tds[1].css('span[id$="VAL_WID"]').text.to_i, :m)
117
- unless (text = tds[1].css('span[id*="SURFACE"]').text.compact).blank?
118
- surface = SURFACES.metch(text)
119
- runway.surface.composition = surface[:composition]
120
- runway.surface.preparation = surface[:preparation]
121
- runway.surface.remarks = surface[:remarks]
122
- end
123
- runway.remarks = tds[7].text.cleanup.blank_to_nil
124
- values = tds[2].text.remove('°').strip.split
125
- runway.forth.geographic_orientation = AIXM.a(values.first.to_i)
126
- runway.back.geographic_orientation = AIXM.a(values.last.to_i) if bidirectional
127
- parts = tds[3].text.strip.split(/\n\s+\n\s+/, 2)
128
- runway.forth.xy = (xy_from(parts[0]) unless parts[0].blank?)
129
- runway.back.xy = (xy_from(parts[1]) unless parts[1].blank?) if bidirectional
130
- values = tds[4].text.strip.split
131
- runway.forth.z = AIXM.z(values.first.to_i, :qnh)
132
- runway.back.z = AIXM.z(values.last.to_i, :qnh) if bidirectional
133
- displaced_thresholds = displaced_thresholds_from(tds[5])
134
- runway.forth.displaced_threshold = displaced_thresholds.first
135
- runway.back.displaced_threshold = displaced_thresholds.last if bidirectional
136
- end
137
- end
138
-
139
- def displaced_thresholds_from(td)
140
- values = td.text.strip.split
141
- case values.count
142
- when 1 then []
143
- when 2 then [AIXM.xy(lat: values[0], long: values[1]), nil]
144
- when 3 then [nil, AIXM.xy(lat: values[1], long: values[2])]
145
- when 4 then [AIXM.xy(lat: values[0], long: values[1]), AIXM.xy(lat: values[2], long: values[3])]
146
- else fail "cannot parse displaced thresholds"
147
- end
148
- end
149
-
150
- patch AIXM::Component::Runway, :width do |parser, object, value|
151
- throw :abort unless value.zero?
152
- airport_id = parser.instance_variable_get(:@airport).id
153
- runway_name = object.name.to_s
154
- throw :abort if (width = parser.fixture.dig('runways', airport_id, runway_name, 'width')).nil?
155
- AIXM.d(width.to_i, :m)
156
- end
157
-
158
- patch AIXM::Component::Runway::Direction, :xy do |parser, object, value|
159
- throw :abort unless value.nil?
160
- airport_id = parser.instance_variable_get(:@airport).id
161
- direction_name = object.name.to_s
162
- throw :abort if (xy = parser.fixture.dig('runways', airport_id, direction_name, 'xy')).nil?
163
- lat, long = xy.split(/\s+/)
164
- AIXM.xy(lat: lat, long: long)
165
- end
166
-
167
- patch AIXM::Component::Surface, :composition do |parser, object, value|
168
- throw :abort unless value.blank?
169
- airport_id = parser.instance_variable_get(:@airport).id
170
- runway_name = parser.instance_variable_get(:@runway).name
171
- throw :abort if (composition = parser.fixture.dig('runways', airport_id, runway_name, 'composition')).nil?
172
- composition
173
- end
174
-
175
- end
176
- end
177
- end