aipp 1.0.0 → 2.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.
- 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
|
|