aipp 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +2 -2
- data/CHANGELOG.md +17 -1
- data/README.md +269 -150
- data/exe/aip2aixm +2 -8
- data/exe/aip2ofmx +2 -8
- data/exe/notam2aixm +5 -0
- data/exe/notam2ofmx +5 -0
- data/lib/aipp/aip/README.md +10 -0
- data/lib/aipp/aip/executable.rb +40 -0
- data/lib/aipp/aip/parser.rb +9 -0
- data/lib/aipp/aip/runner.rb +85 -0
- data/lib/aipp/border.rb +2 -2
- data/lib/aipp/debugger.rb +14 -19
- data/lib/aipp/downloader/file.rb +57 -0
- data/lib/aipp/downloader/graphql.rb +29 -0
- data/lib/aipp/downloader/http.rb +48 -0
- data/lib/aipp/downloader.rb +78 -29
- data/lib/aipp/environment.rb +88 -0
- data/lib/aipp/executable.rb +36 -53
- data/lib/aipp/notam/README.md +25 -0
- data/lib/aipp/notam/executable.rb +27 -0
- data/lib/aipp/notam/parser.rb +9 -0
- data/lib/aipp/notam/runner.rb +28 -0
- data/lib/aipp/parser.rb +133 -160
- data/lib/aipp/patcher.rb +4 -5
- data/lib/aipp/regions/LF/README.md +6 -2
- data/lib/aipp/regions/LF/aip/aerodromes.rb +220 -0
- data/lib/aipp/regions/LF/aip/d_p_r_airspaces.rb +53 -0
- data/lib/aipp/regions/LF/aip/dangerous_activities.rb +48 -0
- data/lib/aipp/regions/LF/aip/designated_points.rb +44 -0
- data/lib/aipp/regions/LF/aip/helipads.rb +119 -0
- data/lib/aipp/regions/LF/aip/navigational_aids.rb +82 -0
- data/lib/aipp/regions/LF/aip/obstacles.rb +150 -0
- data/lib/aipp/regions/LF/aip/serviced_airspaces.rb +67 -0
- data/lib/aipp/regions/LF/aip/services.rb +169 -0
- data/lib/aipp/regions/LF/fixtures/aerodromes.yml +2 -2
- data/lib/aipp/regions/LF/helpers/base.rb +32 -32
- data/lib/aipp/regions/LS/README.md +59 -0
- data/lib/aipp/regions/LS/helpers/base.rb +111 -0
- data/lib/aipp/regions/LS/notam/ENR.rb +173 -0
- data/lib/aipp/runner.rb +152 -0
- data/lib/aipp/version.rb +1 -1
- data/lib/aipp.rb +30 -11
- data/lib/core_ext/array.rb +13 -0
- data/lib/core_ext/nokogiri.rb +56 -8
- data/lib/core_ext/string.rb +63 -1
- data.tar.gz.sig +0 -0
- metadata +115 -64
- metadata.gz.sig +0 -0
- data/lib/aipp/aip.rb +0 -166
- data/lib/aipp/regions/LF/aerodromes.rb +0 -223
- data/lib/aipp/regions/LF/d_p_r_airspaces.rb +0 -56
- data/lib/aipp/regions/LF/dangerous_activities.rb +0 -49
- data/lib/aipp/regions/LF/designated_points.rb +0 -47
- data/lib/aipp/regions/LF/helipads.rb +0 -122
- data/lib/aipp/regions/LF/navigational_aids.rb +0 -85
- data/lib/aipp/regions/LF/obstacles.rb +0 -153
- data/lib/aipp/regions/LF/serviced_airspaces.rb +0 -70
- data/lib/aipp/regions/LF/services.rb +0 -172
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aead3f21ec1e78d23e1c273e6d19f3db92834bb3dccd8ec77f85bf3c279a7a74
|
4
|
+
data.tar.gz: 8c1203247d9a8714fabb704fabbd972364f6c1544b2294b6ae004a59ebf94c74
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '09e058cee67ad5456af31c5cbc93462207303f89857e4bc709d9c09fb9f82212f24db2c59fe1e99a26b0153449f5b347aedd731114b2c549e246a23f270c558a'
|
7
|
+
data.tar.gz: 00c2fdf2386236e31f965317d1d743522adf70a10e80fbf04371ed5c350dcc22f490592ab06d05665a6d8acc55257b458a81cc5c151c031e6b4fc7b4bb04548f
|
checksums.yaml.gz.sig
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
��~@f���x�i�h*���=�L���b�0��'�Ђ2zUh���7�H�4~�]ӧ^� �\�+�0����W-��`������ۡM�n&��*^�Gm��h��킡.�LRi�&��*,�
|
2
|
+
Oʼn�7������E��F���H��;[fp�=���3���%�bS��TP̥��)���,s����Q���d#�Ku�� ����[N���byN{�'TR�i��p��/+S�b�U͂����d:V8��zw
|
data/CHANGELOG.md
CHANGED
@@ -2,10 +2,26 @@
|
|
2
2
|
|
3
3
|
Nothing so far
|
4
4
|
|
5
|
+
## 2.0.0
|
6
|
+
|
7
|
+
#### Additions
|
8
|
+
* Region LS NOTAM
|
9
|
+
* CLI option to set a custom output file
|
10
|
+
* `--quiet` option
|
11
|
+
|
12
|
+
#### Breaking Changes
|
13
|
+
* Drop support for Ruby 3.0
|
14
|
+
* Rename `url_for` to `origin_for` and introduce origin structures which allow
|
15
|
+
for more complex download scenarios such as HTTPS with session or GraphQL.
|
16
|
+
* Overhaul file/class layout to accommodate other than AIP, implement NOTAM.
|
17
|
+
* Cache, borders, fixtures, options and config are now dedicated objects
|
18
|
+
accessible on `AIPP`.
|
19
|
+
* Patches are no longer passed the parser instance.
|
20
|
+
|
5
21
|
## 1.0.0
|
6
22
|
|
7
23
|
#### Breaking Changes
|
8
|
-
* Switch from individual AIP HTML
|
24
|
+
* Switch from individual AIP HTML files to the comprehensive AIP XML
|
9
25
|
database dump for the LF region reference implementation.
|
10
26
|
* Drop the mandatory `URL` helper in favour of a mandatory `url_for` method.
|
11
27
|
* Renamed default git branch to `main`
|
data/README.md
CHANGED
@@ -4,23 +4,22 @@
|
|
4
4
|
|
5
5
|
# AIPP
|
6
6
|
|
7
|
-
Parser for
|
7
|
+
Parser for aeronautical information available online.
|
8
8
|
|
9
|
-
This gem incluces
|
9
|
+
This gem incluces executables to download and parse aeronautical information (HTML, PDF, XSLX, ODS and CSV), then build and export is as [AIXM](https://github.com/svoop/aixm) or [OFMX](https://github.com/openflightmaps/ofmx/wiki).
|
10
10
|
|
11
11
|
* [Homepage](https://github.com/svoop/aipp)
|
12
12
|
* [Rubydoc](https://www.rubydoc.info/gems/aipp/AIPP)
|
13
|
-
* Author: [Sven Schwyn - Bitcetera](
|
13
|
+
* Author: [Sven Schwyn - Bitcetera](https://bitcetera.com)
|
14
14
|
|
15
15
|
## Table of Contents
|
16
16
|
|
17
|
-
[Install](#
|
18
|
-
[Usage](#
|
19
|
-
[
|
20
|
-
[
|
21
|
-
[
|
22
|
-
[
|
23
|
-
[Development](#development)
|
17
|
+
[Install](#label-Install) <br>
|
18
|
+
[Usage](#label-Usage) <br>
|
19
|
+
[Regions](#label-Regions) <br>
|
20
|
+
[Storage](#label-Storage) <br>
|
21
|
+
[References](#label-References) <br>
|
22
|
+
[Development](#label-Development)
|
24
23
|
|
25
24
|
## Install
|
26
25
|
|
@@ -42,10 +41,10 @@ gem install aipp --trust-policy MediumSecurity
|
|
42
41
|
|
43
42
|
### Bundler
|
44
43
|
|
45
|
-
If you're familiar with [Bundler](https://bundler.io) powered Ruby projects, you might prefer to add the following to your <
|
44
|
+
If you're familiar with [Bundler](https://bundler.io) powered Ruby projects, you might prefer to add the following to your <samp>Gemfile</samp> or <samp>gems.rb</samp>:
|
46
45
|
|
47
46
|
```ruby
|
48
|
-
gem aipp
|
47
|
+
gem 'aipp'
|
49
48
|
```
|
50
49
|
|
51
50
|
And then install the bundle:
|
@@ -56,98 +55,117 @@ bundle install --trust-policy MediumSecurity
|
|
56
55
|
|
57
56
|
## Usage
|
58
57
|
|
59
|
-
|
58
|
+
AIPP parses different kind of information sources. The parsers are organized in three levels:
|
60
59
|
|
61
60
|
```
|
62
|
-
|
63
|
-
|
61
|
+
region ⬅︎ aeronautical region such as "LF" (France)
|
62
|
+
└── module ⬅︎ subject area such as "AIP" or "NOTAM"
|
63
|
+
└── section ⬅︎ part of the subject area such as "ENR-2.1" or "aerodromes"
|
64
64
|
```
|
65
65
|
|
66
|
-
|
66
|
+
The following modules are currently available:
|
67
67
|
|
68
|
-
|
69
|
-
|
70
|
-
|
68
|
+
Module | Content | Executables | Cache
|
69
|
+
-------|---------|-------------|------
|
70
|
+
[AIP](lib/aipp/aip/README.md) | aeronautical information publication | `aip2aixm` and `aip2ofmx` | by AIRAC cycle
|
71
|
+
[NOTAM](lib/aipp/notam/README.md) | notice to airmen | `notam2aixm` and `notam2ofmx` | by effective date and hour
|
71
72
|
|
72
|
-
|
73
|
-
|
74
|
-
## Storage
|
75
|
-
|
76
|
-
AIPP uses a storage directory for configuration, caching and in order to keep the results of previous runs. The default location is `~/.aipp`, however, you can pass a different directory with the `--storage` argument.
|
73
|
+
To list all available regions and sections for a given module:
|
77
74
|
|
78
|
-
|
75
|
+
```
|
76
|
+
aip2aixm --list
|
77
|
+
```
|
79
78
|
|
80
|
-
|
81
|
-
* `builds/`<br>This directory contains one ZIP archive per AIRAC cycle which is overwritten on every run. Therefore, to make sure it contains the complete build for a region, you have to make sure that your last run builds the complete AIXM/OFMX for that region. This archive contains:
|
82
|
-
* the built AIXM/OFMX file
|
83
|
-
* `build.yaml` – context of the build process
|
84
|
-
* `manifest.csv` – diffable manifest (see below)
|
85
|
-
* `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.
|
79
|
+
See the built-in help for all options:
|
86
80
|
|
87
|
-
|
81
|
+
```
|
82
|
+
notam2aixm --help
|
83
|
+
```
|
88
84
|
|
89
|
-
|
90
|
-
$ git diff -U0 2019-09-12/manifest.csv 2019-10-10/manifest.csv
|
85
|
+
Example: You wish to build the complete OFMX file for the current AIRAC cycle AIP of the region LF:
|
91
86
|
|
92
|
-
|
93
|
-
|
94
|
-
@@ -204 +204 @@ AD-1.3,Ahp,9e9f031e,d6f22057,Airport: LFLJ COURCHEVEL
|
95
|
-
-AD-1.3,Ahp,9f1eed18,37ddbbde,Airport: LFQD ARRAS ROCLINCOURT
|
96
|
-
+AD-1.3,Ahp,9f1eed18,f0e60105,Airport: LFQD ARRAS ROCLINCOURT
|
97
|
-
@@ -312 +312 @@ AD-2,Aha,4250c9ee,04d49dc7,Address: RADIO for LFHV
|
98
|
-
-AD-2,Aha,6b381b32,fb947716,Address: RADIO for LFPO
|
99
|
-
+AD-2,Aha,6b381b32,b9723b7e,Address: RADIO for LFPO
|
100
|
-
@@ -664 +663,0 @@ AD-2,Ser,3920a7fd,4545c5eb,Service: AFIS by LFGA TWR
|
101
|
-
-AD-2,Ser,39215774,1f13f2cf,Service: APP by LFCR APP
|
102
|
-
@@ -878 +876,0 @@ AD-2,Ser,bb5228d7,7cfb4572,Service: TWR by LFMH TWR
|
103
|
-
-AD-2,Ser,bc72caf2,0a15b39c,Service: FIS by LFCR FIC
|
104
|
-
(...)
|
87
|
+
```
|
88
|
+
aip2ofmx -r LF
|
105
89
|
```
|
106
90
|
|
107
|
-
|
91
|
+
You'll find the OFMX file in the current directory if the binary exits successfully.
|
108
92
|
|
109
93
|
## Regions
|
110
94
|
|
111
|
-
|
95
|
+
To implement a region, you have to create a directory <samp>lib/aipp/regions/{REGION}/</samp> off the gem root and then subdirectories for each module as well as for support files. Here's a simplified overview for the region "LF" (France):
|
112
96
|
|
113
|
-
|
97
|
+
```
|
98
|
+
LF/ ⬅︎ region "LF"
|
99
|
+
├── README.md
|
100
|
+
├── aip ⬅︎ module "AIP"
|
101
|
+
│ ├── AD-2.rb ⬅︎ section "AD-2"
|
102
|
+
│ └── ENR-4.3.rb ⬅︎ section "ENR-4.3"
|
103
|
+
├── notam ⬅︎ module "NOTAM"
|
104
|
+
│ ├── AD.rb ⬅︎ section "AD"
|
105
|
+
│ └── ENR.rb ⬅︎ section "ENR"
|
106
|
+
├── borders
|
107
|
+
│ ├── france_atlantic_coast.geojson
|
108
|
+
│ └── france_atlantic_territorial_sea.geojson
|
109
|
+
├── fixtures
|
110
|
+
│ └── aerodromes.yml
|
111
|
+
└── helpers
|
112
|
+
├── base.rb
|
113
|
+
└── surface.rb
|
114
|
+
```
|
114
115
|
|
115
|
-
|
116
|
+
<table>
|
117
|
+
<tr>
|
118
|
+
<td>⚠️</td>
|
119
|
+
<td>All paths from here on forward are relative to the region directory.</td>
|
120
|
+
</tr>
|
121
|
+
</table>
|
116
122
|
|
117
|
-
|
123
|
+
### Parsers
|
124
|
+
|
125
|
+
Say, you want to parse AIP ENR-4.1. You have to create the file <samp>aip/ENR-4.1.rb</samp> which defines the class `ENR41` as follows:
|
118
126
|
|
119
127
|
```ruby
|
120
|
-
module AIPP
|
121
|
-
|
122
|
-
|
128
|
+
module AIPP::LF::AIP
|
129
|
+
class ENR41 < AIPP::AIP::Parser
|
130
|
+
depends_on :ENR21, :ENR22 # declare dependencies to other parsers
|
131
|
+
(...)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
```
|
123
135
|
|
124
|
-
|
136
|
+
Another parser might target en-route NOTAM and therefore has to go to <samp>notam/ENR.rb</samp> like so:
|
125
137
|
|
126
|
-
|
138
|
+
```ruby
|
139
|
+
module AIPP::LF::NOTAM
|
140
|
+
class ENR < AIPP::NOTAM::Parser
|
141
|
+
(...)
|
127
142
|
end
|
128
143
|
end
|
129
144
|
```
|
130
145
|
|
131
|
-
|
146
|
+
<table>
|
147
|
+
<tr>
|
148
|
+
<td>⚠️</td>
|
149
|
+
<td>Parser files and classes may follow AIP naming conventions such as <samp>ENR-4.1.rb</samp>. However, you're free to use arbitrary naming for parser files like <samp>navaids.rb</samp> (e.g. if you're working with one big data source which contains the full AIP dataset you'd like to split into smaller parts).</td>
|
150
|
+
</tr>
|
151
|
+
</table>
|
132
152
|
|
133
|
-
|
153
|
+
The class has to implement some methods either in the class itself or in a [helper](#Helpers) included by the class.
|
134
154
|
|
135
155
|
#### Mandatory `parse` Method
|
136
156
|
|
137
157
|
The class must implement the `parse` method which contains the code to read, parse and write the data:
|
138
158
|
|
139
159
|
```ruby
|
140
|
-
module AIPP
|
141
|
-
|
142
|
-
class ENR43 < AIP
|
143
|
-
|
144
|
-
def parse
|
145
|
-
html = read # read the Nokogiri::HTML5 document
|
146
|
-
feature = (...) # build the feature
|
147
|
-
add(feature: feature) # add the feature to AIXM::Document
|
148
|
-
end
|
160
|
+
module AIPP::LF::AIP
|
161
|
+
class ENR41 < AIPP::AIP::Parser
|
149
162
|
|
163
|
+
def parse
|
164
|
+
html = read # read the Nokogiri::HTML5 document
|
165
|
+
feature = (...) # build the feature
|
166
|
+
add(feature: feature) # add the feature to AIXM::Document
|
150
167
|
end
|
168
|
+
|
151
169
|
end
|
152
170
|
end
|
153
171
|
```
|
@@ -155,95 +173,171 @@ end
|
|
155
173
|
Some AIP may be split over several files which require a little more code to load the individual HTML source files:
|
156
174
|
|
157
175
|
```ruby
|
158
|
-
module AIPP
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
(...)
|
167
|
-
end
|
176
|
+
module AIPP::LF::AIP
|
177
|
+
class AD2 < AIPP::AIP::Parser
|
178
|
+
|
179
|
+
def parse
|
180
|
+
%i(one two three).each do |part|
|
181
|
+
html = read("#{aip}.#{part}") # read with a non-standard name
|
182
|
+
support_html = read('AD-0.6') # maybe read necessary support documents
|
183
|
+
(...)
|
168
184
|
end
|
169
|
-
|
170
185
|
end
|
186
|
+
|
171
187
|
end
|
172
188
|
end
|
173
189
|
```
|
174
190
|
|
175
|
-
|
191
|
+
The parser has access to the following methods:
|
176
192
|
|
177
193
|
Method | Description
|
178
194
|
-------|------------
|
179
|
-
[`
|
180
|
-
[`
|
181
|
-
[`
|
182
|
-
[`
|
183
|
-
[`
|
184
|
-
[`
|
185
|
-
[`
|
186
|
-
[`
|
187
|
-
[`aip`](https://www.rubydoc.info/gems/aipp/AIPP%2FAIP:aip) | AIP name (equal to the parser file name without its file extension such as "ENR-2.1" implemented in the file "ENR-2.1.rb")
|
188
|
-
[`aip_file`](https://www.rubydoc.info/gems/aipp/AIPP%2FAIP:aip_file) | AIP file as passed and possibly renamed by `url_for`
|
189
|
-
[`options`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#options-instance_method) | arguments read from <tt>aip2aixm</tt> or <tt>aip2ofmx</tt> respectively
|
190
|
-
[`config`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#config-instance_method) | configuration read from <tt>config.yml</tt>
|
191
|
-
[`borders`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#borders-instance_method) | borders defined as GeoJSON read from the region (see below)
|
192
|
-
[`cache`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#cache-instance_method) | `OStruct` instance to make objects available across AIPs
|
193
|
-
|
194
|
-
To make the parser code more readable, this gem provides a few useful core extensions as well:
|
195
|
+
[`section`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#section-instance_method) | current section (e.g. `ENR-2.1` or `aerodromes`)
|
196
|
+
[`read`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#read-instance_method) | download, cache and read a document from source
|
197
|
+
[`add`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#add-instance_method) | add a [`AIXM::Feature`](https://www.rubydoc.info/gems/aixm/AIXM/Feature)
|
198
|
+
[`find`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#find-instance_method) | find previously written [`AIXM::Feature`](https://www.rubydoc.info/gems/aixm/AIXM/Feature)s by object
|
199
|
+
[`find_by`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#find_by-instance_method) | find previously written [`AIXM::Feature`](https://www.rubydoc.info/gems/aixm/AIXM/Feature)s by class and attribute values
|
200
|
+
[`unique`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#unique-instance_method) | prevent duplicate [`AIXM::Feature`](https://www.rubydoc.info/gems/aixm/AIXM/Feature)s
|
201
|
+
[`given`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#given-instance_method) | inline condition for assignments
|
202
|
+
[`link_to`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#link_to-instance_method) | optionally checked Markdown link
|
195
203
|
|
204
|
+
Equally available is the current runtime environment. All of the following objects behave like `OpenStruct`:
|
205
|
+
|
206
|
+
Method | Description
|
207
|
+
-------|------------
|
208
|
+
[`AIPP.cache`](https://www.rubydoc.info/gems/aipp/AIPP/Enrivonment/Cache) | cache to make transient objects available across AIPs
|
209
|
+
[`AIPP.borders`](https://www.rubydoc.info/gems/aipp/AIPP/Enrivonment/Borders) | [borders](#Borders) of the current region
|
210
|
+
[`AIPP.fixtures`](https://www.rubydoc.info/gems/aipp/AIPP/Enrivonment/Fixtures) | [fixtures](#Fixtures) of the current region
|
211
|
+
[`AIPP.options`](https://www.rubydoc.info/gems/aipp/AIPP/Environment/Options) | arguments read from <samp>aip2aixm</samp> or <samp>aip2ofmx</samp> respectively
|
212
|
+
[`AIPP.config`](https://www.rubydoc.info/gems/aipp/AIPP/Environment/Config) | configuration read from <samp>config.yml</samp>
|
213
|
+
|
214
|
+
To make the parser code more readable, a few core extensions are provided:
|
215
|
+
|
216
|
+
* [`Object#blank` (ActiveSupport)](https://www.rubydoc.info/gems/activesupport/Object#blank%3F-instance_method)
|
196
217
|
* [`NilClass`](https://www.rubydoc.info/gems/aipp/NilClass)
|
197
218
|
* [`Integer`](https://www.rubydoc.info/gems/aipp/Integer)
|
219
|
+
* [`String` (ActiveSupport)](https://www.rubydoc.info/gems/activesupport/String)
|
198
220
|
* [`String`](https://www.rubydoc.info/gems/aipp/String)
|
221
|
+
* [`Array`](https://www.rubydoc.info/gems/aipp/Array)
|
199
222
|
* [`Hash`](https://www.rubydoc.info/gems/aipp/Hash)
|
200
223
|
* [`Enumerable`](https://www.rubydoc.info/gems/aipp/Enumerable)
|
224
|
+
* [`DateTime` (ActiveSupport)](https://www.rubydoc.info/gems/activesupport/DateTime)
|
201
225
|
* [`Nokogiri`](https://www.rubydoc.info/gems/aipp/Nokogiri)
|
202
226
|
|
203
|
-
#### Mandatory `
|
227
|
+
#### Mandatory `origin_for` Method
|
204
228
|
|
205
|
-
The class must implement the `
|
229
|
+
The class must implement the `origin_for` method which returns an origin object describing how to download the source data (e.g. an AIP file or NOTAM message):
|
206
230
|
|
207
231
|
```ruby
|
208
|
-
module AIPP
|
209
|
-
|
210
|
-
class AD2 < AIP
|
211
|
-
|
212
|
-
def url_for(aip_file)
|
213
|
-
# build and return the download URL for the aip file
|
214
|
-
end
|
232
|
+
module AIPP::LF::AIP
|
233
|
+
class AD2 < AIPP::AIP::Parser
|
215
234
|
|
235
|
+
def origin_for(document)
|
236
|
+
# build and return the origin object
|
216
237
|
end
|
238
|
+
|
217
239
|
end
|
218
240
|
end
|
219
241
|
```
|
220
242
|
|
221
|
-
|
243
|
+
Return any of the following origin objects best explained by example:
|
222
244
|
|
223
|
-
|
224
|
-
|
225
|
-
|
245
|
+
```
|
246
|
+
AIPP::Downloader::File.new(
|
247
|
+
file: "file.dat", # relative path to file
|
248
|
+
type: :pdf # optional: file type if different from extension
|
249
|
+
)
|
250
|
+
```
|
226
251
|
|
227
|
-
|
252
|
+
```
|
253
|
+
AIPP::Downloader::File.new(
|
254
|
+
archive: "foobar.zip", # relative path to archive
|
255
|
+
file: "subdir/file.dat", # file to extract from archive
|
256
|
+
type: :pdf # optional: file type if different from extension
|
257
|
+
)
|
258
|
+
```
|
228
259
|
|
229
|
-
|
260
|
+
See [Downloader](https://www.rubydoc.info/gems/aipp/AIPP/Downloader) for more on recognised file and archive types.
|
230
261
|
|
262
|
+
```
|
263
|
+
AIPP::Downloader::HTTP.new(
|
264
|
+
file: "https://example.com/foobar.zip", # URL where the file is located
|
265
|
+
type: :pdf, # optional: file type if different from extension
|
266
|
+
headers: "Cookie: name=value", # optional: additional headers e.g. for session
|
267
|
+
)
|
268
|
+
```
|
269
|
+
|
270
|
+
```
|
271
|
+
AIPP::Downloader::HTTP.new(
|
272
|
+
archive: "https://example.com/foobar.zip", # URL where the archive is located
|
273
|
+
file: "subdir/file.dat", # file to extract from archive
|
274
|
+
type: :pdf, # optional: file type if different from extension
|
275
|
+
headers: "Cookie: name=value", # optional: additional headers e.g. for session
|
276
|
+
)
|
277
|
+
```
|
278
|
+
|
279
|
+
The [excon gem](https://www.rubydoc.info/gems/excon) is used to perform HTTP requests.
|
280
|
+
|
281
|
+
```
|
282
|
+
AIPP::Downloader::GraphQL.new(
|
283
|
+
client: MyAPI::Client, # GraphQL client class
|
284
|
+
query: MyAPI::Name::Query, # GraphQL query class
|
285
|
+
variables: { # dynamic query parameters
|
286
|
+
first_name: 'Geronimo',
|
287
|
+
age: 50
|
288
|
+
}
|
289
|
+
)
|
290
|
+
```
|
291
|
+
|
292
|
+
For this GraphQL downloader to work, you have to declare a GraphQL client class beforehand. See the [graphql-client gem documentation](https://www.rubydoc.info/gems/graphql-client) for details, the following example fits the downloader above:
|
231
293
|
|
232
294
|
```ruby
|
233
|
-
module
|
234
|
-
|
235
|
-
|
295
|
+
module MyAPI
|
296
|
+
HttpAdapter = GraphQL::Client::HTTP.new(ENV['MY_API_URL']) do
|
297
|
+
def headers(context)
|
298
|
+
{ "Authorization": "Bearer #{ENV['MY_API_AUTHORIZATION']}" }
|
299
|
+
end
|
300
|
+
end
|
301
|
+
Schema = GraphQL::Client.load_schema(HttpAdapter)
|
302
|
+
Client = GraphQL::Client.new(schema: Schema, execute: HttpAdapter)
|
303
|
+
|
304
|
+
class Name
|
305
|
+
Query = Client.parse <<~END
|
306
|
+
query ($first_name: String!, $age: Int!) {
|
307
|
+
queryNOTAMs(
|
308
|
+
filter: {first_name: $first_name, age: $age}
|
309
|
+
) {
|
310
|
+
name
|
311
|
+
}
|
312
|
+
}
|
313
|
+
END
|
314
|
+
end
|
315
|
+
end
|
316
|
+
```
|
236
317
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
318
|
+
For performance, all downloads are cached and subsequent runs will use the cached data rather than fetching the sources anew. Each module defines a cache time window, see the [table of modules above](#label-Usage). You can discard existing and rebuild caches by use of the `--clean` command line argument.
|
319
|
+
|
320
|
+
#### Optional `setup` Method
|
321
|
+
|
322
|
+
The class may implement the `setup` method. If present, it will be called when this parser is instantiated:
|
241
323
|
|
324
|
+
```ruby
|
325
|
+
module AIPP::LF::AIP
|
326
|
+
class AD2 < AIPP::AIP::Parser
|
327
|
+
|
328
|
+
def setup
|
329
|
+
AIXM.config.voice_channel_separation = :any
|
330
|
+
AIPP.cache.setup_at ||= Time.now
|
242
331
|
end
|
332
|
+
|
243
333
|
end
|
244
334
|
end
|
245
335
|
```
|
246
336
|
|
337
|
+
### Helpers
|
338
|
+
|
339
|
+
Helpers are mixins defined in the <samp>helpers/</samp> subdirectory. All helpers are required automatically in alphabetic order.
|
340
|
+
|
247
341
|
### Borders
|
248
342
|
|
249
343
|
AIXM knows named borders for country boundaries. However, you might need additional borders which don't exist as named borders.
|
@@ -252,7 +346,7 @@ You can define additional borders as [`AIPP::Border`](https://www.rubydoc.info/g
|
|
252
346
|
|
253
347
|
#### From GeoJSON
|
254
348
|
|
255
|
-
Create simple GeoJSON files in the <
|
349
|
+
Create simple GeoJSON files in the <samp>borders/</samp> subdirectory, for example this `my_border_1.geojson`:
|
256
350
|
|
257
351
|
```json
|
258
352
|
{
|
@@ -276,7 +370,12 @@ Create simple GeoJSON files in the <tt>lib/aipp/regions/{REGION}/borders/</tt> d
|
|
276
370
|
}
|
277
371
|
```
|
278
372
|
|
279
|
-
|
373
|
+
<table>
|
374
|
+
<tr>
|
375
|
+
<td>⚠️</td>
|
376
|
+
<td>The GeoJSON file must consist of exactly one `GeometryCollection` which may contain any number of `LineString` geometries. Only `LineString` geometries are recognised! To define a closed polygon, the first coordinates of a `LineString` must be identical to the last coordinates.</td
|
377
|
+
</tr>
|
378
|
+
</table>
|
280
379
|
|
281
380
|
#### From Coordinates
|
282
381
|
|
@@ -309,28 +408,26 @@ The border object implements simple nearest point and segment calculations to cr
|
|
309
408
|
|
310
409
|
See [`AIPP::Border`](https://www.rubydoc.info/gems/aipp/AIPP/Border) for more on this.
|
311
410
|
|
312
|
-
###
|
411
|
+
### Fixtures
|
313
412
|
|
314
|
-
|
413
|
+
Fixtures are static YAML data files in the <samp>fixtures/</samp> subdirectory. All fixtures are read automatically, e.g. the contents of the <samp>lib/aipp/regions/{REGION}/fixtures/aerodromes.yml</samp> will be available from `AIPP.fixtures.aerodromes`.
|
315
414
|
|
316
|
-
|
415
|
+
Read on for how to best use fixtures.
|
317
416
|
|
318
|
-
|
417
|
+
### Patches
|
319
418
|
|
320
|
-
When parsed data is faulty or missing, you may fall back to
|
419
|
+
When parsed data is faulty or missing, you may fall back to fixtures instead. This is where patches come in. You can patch any AIXM attribute setter by defining a patch block inside the AIP parser and accessing the static data via `parser.fixture`:
|
321
420
|
|
322
421
|
```ruby
|
323
|
-
module AIPP
|
324
|
-
|
325
|
-
class AD2 < AIP
|
326
|
-
|
327
|
-
patch AIXM::Feature::Airport, :z do |parser, object, value|
|
328
|
-
throw(:abort) unless value.nil?
|
329
|
-
throw(:abort, 'fixture missing') unless z = parser.fixture.dig(object.id, 'z')
|
330
|
-
AIXM.z(z, :qnh)
|
331
|
-
end
|
422
|
+
module AIPP::LF::AIP
|
423
|
+
class AD2 < AIP
|
332
424
|
|
425
|
+
patch AIXM::Feature::Airport, :z do |object, value|
|
426
|
+
throw(:abort) unless value.nil?
|
427
|
+
throw(:abort, 'fixture missing') unless z = AIPP.fixtures.aerodromes.dig(object.id, 'z')
|
428
|
+
AIXM.z(z, :qnh)
|
333
429
|
end
|
430
|
+
|
334
431
|
end
|
335
432
|
end
|
336
433
|
```
|
@@ -341,12 +438,6 @@ The patch receives the object and the value which is about to be assigned. It sh
|
|
341
438
|
* Otherwise, try to fetch a better value e.g. from the fixtures. If no better value can be found (e.g. outdated fixtures), `throw(:abort, "reason")` to leave the patch block and fail with a useful error message which contains the reason thrown.
|
342
439
|
* At last, build and return the value object which will be assigned instead of the original value.
|
343
440
|
|
344
|
-
In case the `object` does not carry enough details, you can access instance variables of the parser like so:
|
345
|
-
|
346
|
-
```ruby
|
347
|
-
parser.instance_variable_get(:@instance_variable)
|
348
|
-
```
|
349
|
-
|
350
441
|
### Source File Line Numbers
|
351
442
|
|
352
443
|
In order to reference the source of an AIXM/OFMX feature, it's necessary to know the line number where a particular node occurs in the HTML source file. You can ask any HTML element as follows:
|
@@ -369,7 +460,12 @@ You should `warn` on non-fatal problems which should be fixed (default) or might
|
|
369
460
|
|
370
461
|
```ruby
|
371
462
|
warn("my message")
|
372
|
-
|
463
|
+
```
|
464
|
+
|
465
|
+
Less important warnings are only shown if the `--verbose` mode is set:
|
466
|
+
|
467
|
+
```ruby
|
468
|
+
warn("my message", severe: false)
|
373
469
|
```
|
374
470
|
|
375
471
|
### Messages
|
@@ -399,18 +495,41 @@ The [default Ruby debugger](https://github.com/ruby/debug#debug-command-on-the-d
|
|
399
495
|
debugger
|
400
496
|
```
|
401
497
|
|
402
|
-
##
|
498
|
+
## Storage
|
499
|
+
|
500
|
+
AIPP uses a storage directory for configuration, caching and in order to keep the results of previous runs. The default location is `~/.aipp`, however, you can pass a different directory with the `--storage` argument.
|
403
501
|
|
404
|
-
|
502
|
+
You'll find a directory for each region and module which contains the following items:
|
405
503
|
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
504
|
+
* `sources/`<br>ZIP archives which cache all source files used to build.
|
505
|
+
* `builds/`<br>ZIP archives of successful builds containing:
|
506
|
+
* the built AIXM/OFMX file
|
507
|
+
* `build.yaml` – context of the build process
|
508
|
+
* `manifest.csv` – diffable manifest (see below)
|
509
|
+
* `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.
|
510
|
+
|
511
|
+
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:
|
512
|
+
|
513
|
+
```diff
|
514
|
+
$ git diff -U0 2019-09-12/manifest.csv 2019-10-10/manifest.csv
|
515
|
+
|
516
|
+
--- a/2019-09-12/manifest.csv
|
517
|
+
+++ b/2019-10-10/manifest.csv
|
518
|
+
@@ -204 +204 @@ AD-1.3,Ahp,9e9f031e,d6f22057,Airport: LFLJ COURCHEVEL
|
519
|
+
-AD-1.3,Ahp,9f1eed18,37ddbbde,Airport: LFQD ARRAS ROCLINCOURT
|
520
|
+
+AD-1.3,Ahp,9f1eed18,f0e60105,Airport: LFQD ARRAS ROCLINCOURT
|
521
|
+
@@ -312 +312 @@ AD-2,Aha,4250c9ee,04d49dc7,Address: RADIO for LFHV
|
522
|
+
-AD-2,Aha,6b381b32,fb947716,Address: RADIO for LFPO
|
523
|
+
+AD-2,Aha,6b381b32,b9723b7e,Address: RADIO for LFPO
|
524
|
+
@@ -664 +663,0 @@ AD-2,Ser,3920a7fd,4545c5eb,Service: AFIS by LFGA TWR
|
525
|
+
-AD-2,Ser,39215774,1f13f2cf,Service: APP by LFCR APP
|
526
|
+
@@ -878 +876,0 @@ AD-2,Ser,bb5228d7,7cfb4572,Service: TWR by LFMH TWR
|
527
|
+
-AD-2,Ser,bc72caf2,0a15b39c,Service: FIS by LFCR FIC
|
528
|
+
(...)
|
412
529
|
```
|
413
530
|
|
531
|
+
The advantage of `git diff` is its ability to highlight exactly which part of a line has changed. [Check out this post to learn how](https://www.viget.com/articles/dress-up-your-git-diffs-with-word-level-highlights/).
|
532
|
+
|
414
533
|
## References
|
415
534
|
|
416
535
|
* [Geo Maps – programmatically generated GeoJSON maps](https://github.com/simonepri/geo-maps)
|
@@ -431,7 +550,7 @@ Please submit issues on:
|
|
431
550
|
|
432
551
|
https://github.com/svoop/aipp/issues
|
433
552
|
|
434
|
-
To contribute code, fork the project on
|
553
|
+
To contribute code, fork the project on GitHub, add your code and submit a pull request:
|
435
554
|
|
436
555
|
https://help.github.com/articles/fork-a-repo
|
437
556
|
|