aipp 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/CHANGELOG.md +9 -0
- data/README.md +47 -13
- data/TODO.md +5 -2
- data/aipp.gemspec +1 -1
- data/lib/aipp.rb +2 -0
- data/lib/aipp/aip.rb +4 -3
- data/lib/aipp/border.rb +146 -0
- data/lib/aipp/downloader.rb +1 -1
- data/lib/aipp/executable.rb +2 -2
- data/lib/aipp/parser.rb +12 -1
- data/lib/aipp/patcher.rb +1 -1
- data/lib/aipp/pdf.rb +5 -5
- data/lib/aipp/regions/LF/AD-1.3.rb +4 -4
- data/lib/aipp/regions/LF/AD-1.6.rb +1 -1
- data/lib/aipp/regions/LF/AD-2.rb +7 -7
- data/lib/aipp/regions/LF/ENR-2.1.rb +9 -7
- data/lib/aipp/regions/LF/ENR-4.1.rb +2 -7
- data/lib/aipp/regions/LF/ENR-4.3.rb +1 -1
- data/lib/aipp/regions/LF/ENR-5.1.rb +2 -2
- data/lib/aipp/regions/LF/ENR-5.5.rb +53 -0
- data/lib/aipp/regions/LF/borders/france_atlantic_coast.geojson +2546 -0
- data/lib/aipp/regions/LF/borders/france_atlantic_territorial_sea.geojson +1663 -0
- data/lib/aipp/regions/LF/borders/france_ecrins_national_park.geojson +5861 -0
- data/lib/aipp/regions/LF/borders/france_mediterranean_coast.geojson +6203 -0
- data/lib/aipp/regions/LF/helpers/common.rb +26 -16
- data/lib/aipp/version.rb +1 -1
- data/lib/core_ext/integer.rb +16 -0
- data/lib/core_ext/object.rb +4 -4
- data/spec/fixtures/border.geojson +201 -0
- data/spec/lib/aipp/border_spec.rb +135 -0
- data/spec/lib/core_ext/integer_spec.rb +15 -0
- metadata +17 -5
- data/lib/aipp/regions/LF/ENR-5.5.rb-NEW +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d97409845a7b08285c77294aa116873fdcb668bd0f10d13d2ceecd9ef3922a9
|
4
|
+
data.tar.gz: 2594b4ad9bd0b9deba766704778ff1710eaaf71ce675bb4fd378481f4f13dfc6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa0ac5dafcc6e36a113e2a97c270f768265379b09c34a833e785adf44f45e5dfcd5bb3951b0d6741ae15bc765386eb55c3118154a48ce568f9fae14f06bf6ae5
|
7
|
+
data.tar.gz: 92dd8d6134a1882b0ceada8e130ed834e3dc866e4b84e2dd513084c5313a42d8fd89b47d3726ff36e1f38bb8837fa190790bcc3f99d752e7504757e1a2b4eb84
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -51,9 +51,9 @@ module AIPP
|
|
51
51
|
DEPENDS = %w(ENR-2.1 ENR-2.2) # declare dependencies to other AIPs
|
52
52
|
|
53
53
|
def parse
|
54
|
-
html = read
|
55
|
-
feature = (...)
|
56
|
-
|
54
|
+
html = read # read the Nokogiri::HTML5 document
|
55
|
+
feature = (...) # build the feature
|
56
|
+
add(feature: feature) # add the feature to AIXM::Document
|
57
57
|
end
|
58
58
|
|
59
59
|
end
|
@@ -84,16 +84,50 @@ end
|
|
84
84
|
Inside the `parse` method, you have access to the following methods:
|
85
85
|
|
86
86
|
* [`read`](https://www.rubydoc.info/gems/aipp/AIPP/AIP#read-instance_method) – download and read an AIP file
|
87
|
-
* [`
|
88
|
-
* [`select`](https://www.rubydoc.info/gems/aipp/AIPP/AIP#find-instance_method – search previously written [`AIXM::Feature`s](
|
87
|
+
* [`add`](https://www.rubydoc.info/gems/aipp/AIPP/AIP#add-instance_method) – add a [`AIXM::Feature`](https://www.rubydoc.info/gems/aixm/AIXM/Feature)
|
88
|
+
* [`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)
|
89
89
|
* 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)
|
90
|
-
* core extensions from this gem – [`Object`](https://www.rubydoc.info/gems/aipp/Object), [`String`](https://www.rubydoc.info/gems/aipp/String), [`NilClass`](https://www.rubydoc.info/gems/aipp/NilClass) and [`Enumerable`](https://www.rubydoc.info/gems/aipp/Enumerable)
|
90
|
+
* core extensions from this gem – [`Object`](https://www.rubydoc.info/gems/aipp/Object), [`Integer`](https://www.rubydoc.info/gems/aipp/Integer), [`String`](https://www.rubydoc.info/gems/aipp/String), [`NilClass`](https://www.rubydoc.info/gems/aipp/NilClass) and [`Enumerable`](https://www.rubydoc.info/gems/aipp/Enumerable)
|
91
|
+
|
92
|
+
As well as the following methods:
|
93
|
+
|
94
|
+
* [`options`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#options-instance_method) – arguments read from <tt>aip2aixm</tt> or <tt>aip2ofmx</tt> respectively
|
95
|
+
* [`config`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#config-instance_method) – configuration read from <tt>config.yml</tt>
|
96
|
+
* [`borders`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#borders-instance_method) – borders defined as GeoJSON read from the region (see below)
|
97
|
+
* [`cache`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#cache-instance_method) – virgin `OStruct` instance to make objects available across AIPs
|
98
|
+
|
99
|
+
### Borders
|
100
|
+
|
101
|
+
AIXM knows named borders for country boundaries. However, you might need additional borders which don't exist as named boarders.
|
102
|
+
|
103
|
+
To define additional borders, create simple GeoJSON files in the <tt>lib/aipp/regions/{REGION}/borders/</tt> directory, for example this `custom_border.geojson`:
|
104
|
+
|
105
|
+
```json
|
106
|
+
{
|
107
|
+
"type": "GeometryCollection",
|
108
|
+
"geometries": [
|
109
|
+
{
|
110
|
+
"type": "LineString",
|
111
|
+
"coordinates": [
|
112
|
+
[6.009531650000042, 45.12013319700009],
|
113
|
+
[6.015747738000073, 45.12006702600007]
|
114
|
+
]
|
115
|
+
}
|
116
|
+
]
|
117
|
+
}
|
118
|
+
```
|
119
|
+
|
120
|
+
⚠️ The GeoJSON file must consist of exactly one `GeometryCollection` which may contain any number of `LineString` geometries. Only `LineString` geometries are recognized! To define a closed polygon, the first coordinates of a `LineString` must be identical to the last coordinates.
|
121
|
+
|
122
|
+
The [`borders`](https://www.rubydoc.info/gems/aipp/AIPP/Parser#borders-instance_method) method gives you access to a map from the border name (upcased file name) to the corresponding [`AIPP::Border`](https://www.rubydoc.info/gems/aipp/AIPP/Border) object:
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
borders # => { "CUSTOM_BORDER" => #<AIPP::Border file=custom_border.geojson> }
|
126
|
+
```
|
91
127
|
|
92
|
-
|
128
|
+
The border object implements simple nearest point and segment calculations to create arrays of [`AIXM::XY`](https://www.rubydoc.info/gems/aixm/AIXM/XY) which can be used with [`AIXM::Component::Geometry`](https://www.rubydoc.info/gems/aixm/AIXM/Component/Geometry).
|
93
129
|
|
94
|
-
|
95
|
-
* `config` – configuration read from <tt>config.yml</tt>
|
96
|
-
* `cache` – virgin `OStruct` instance to make objects available across AIPs
|
130
|
+
See [`AIPP::Border`](https://www.rubydoc.info/gems/aipp/AIPP/Border) for more on this.
|
97
131
|
|
98
132
|
### Helpers
|
99
133
|
|
@@ -213,12 +247,12 @@ info("my message") # displays "my message" in black
|
|
213
247
|
info("my message", color: :green) # displays "my message" in green
|
214
248
|
```
|
215
249
|
|
216
|
-
####
|
250
|
+
#### verbose info
|
217
251
|
|
218
|
-
Use `
|
252
|
+
Use `verbose_info` for in-depth info messages which are only shown if the `--verbose` mode is set:
|
219
253
|
|
220
254
|
```ruby
|
221
|
-
|
255
|
+
verbose_info("my message") # displays "my message" in blue
|
222
256
|
```
|
223
257
|
|
224
258
|
### Pry
|
data/TODO.md
CHANGED
data/aipp.gemspec
CHANGED
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_development_dependency 'guard'
|
31
31
|
spec.add_development_dependency 'guard-minitest'
|
32
32
|
|
33
|
-
spec.add_runtime_dependency 'aixm', '>= 0.3.
|
33
|
+
spec.add_runtime_dependency 'aixm', '>= 0.3.5'
|
34
34
|
spec.add_runtime_dependency 'activesupport', '~> 5'
|
35
35
|
spec.add_runtime_dependency 'nokogiri', '~> 1'
|
36
36
|
spec.add_runtime_dependency 'nokogumbo', '~> 2'
|
data/lib/aipp.rb
CHANGED
@@ -21,12 +21,14 @@ require 'active_support'
|
|
21
21
|
require 'active_support/core_ext/object/blank'
|
22
22
|
require 'active_support/core_ext/string'
|
23
23
|
require_relative 'core_ext/object'
|
24
|
+
require_relative 'core_ext/integer'
|
24
25
|
require_relative 'core_ext/string'
|
25
26
|
require_relative 'core_ext/nil_class'
|
26
27
|
require_relative 'core_ext/enumerable'
|
27
28
|
|
28
29
|
require_relative 'aipp/version'
|
29
30
|
require_relative 'aipp/pdf'
|
31
|
+
require_relative 'aipp/border'
|
30
32
|
require_relative 'aipp/t_hash'
|
31
33
|
require_relative 'aipp/executable'
|
32
34
|
require_relative 'aipp/airac'
|
data/lib/aipp/aip.rb
CHANGED
@@ -20,7 +20,7 @@ module AIPP
|
|
20
20
|
# @see AIPP::Parser#options
|
21
21
|
# @!method cache
|
22
22
|
# @see AIPP::Parser#cache
|
23
|
-
def_delegators :@parser, :aixm, :config, :options, :cache
|
23
|
+
def_delegators :@parser, :aixm, :config, :options, :borders, :cache
|
24
24
|
private :aixm
|
25
25
|
|
26
26
|
def initialize(aip:, downloader:, parser:)
|
@@ -45,10 +45,11 @@ module AIPP
|
|
45
45
|
@downloader.read(document: aip_file, url: url_for(aip_file))
|
46
46
|
end
|
47
47
|
|
48
|
-
#
|
48
|
+
# Add feature to AIXM
|
49
49
|
#
|
50
50
|
# @param feature [AIXM::Feature] e.g. airport or airspace
|
51
|
-
def
|
51
|
+
def add(feature)
|
52
|
+
verbose_info "Adding #{feature.class}"
|
52
53
|
aixm.features << feature
|
53
54
|
end
|
54
55
|
|
data/lib/aipp/border.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
module AIPP
|
2
|
+
|
3
|
+
# Border GeoJSON file reader
|
4
|
+
#
|
5
|
+
# The border GeoJSON files must be a geometry collection of one or more
|
6
|
+
# line strings:
|
7
|
+
#
|
8
|
+
# {
|
9
|
+
# "type": "GeometryCollection",
|
10
|
+
# "geometries": [
|
11
|
+
# {
|
12
|
+
# "type": "LineString",
|
13
|
+
# "coordinates": [
|
14
|
+
# [6.009531650000042, 45.12013319700009],
|
15
|
+
# [6.015747738000073, 45.12006702600007]
|
16
|
+
# ]
|
17
|
+
# }
|
18
|
+
# ]
|
19
|
+
# }
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# border = AIPP::Border.new("/path/to/file.geojson")
|
23
|
+
# border.geometries
|
24
|
+
# # => [[#<AIXM::XY 45.12013320N 006.00953165E>, <AIXM::XY 45.12006703N 006.01574774E>]]
|
25
|
+
class Border
|
26
|
+
attr_reader :file
|
27
|
+
attr_reader :geometries
|
28
|
+
|
29
|
+
def initialize(file)
|
30
|
+
@file = file.is_a?(Pathname) ? file : Pathname(file)
|
31
|
+
fail(ArgumentError, "file must have extension .geojson") unless @file.extname == '.geojson'
|
32
|
+
@geometries = load_geometries
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [String]
|
36
|
+
def inspect
|
37
|
+
%Q(#<#{self.class} file=#{@file}>)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Name of the border
|
41
|
+
#
|
42
|
+
# By convention, the name of the border is taken from the filename with
|
43
|
+
# both the extension .geojson and all non alphanumeric characters dropped
|
44
|
+
# and the resulting string upcased.
|
45
|
+
#
|
46
|
+
# @return [String]
|
47
|
+
def name
|
48
|
+
@file.basename('.geojson').to_s.gsub(/\W/, '').upcase
|
49
|
+
end
|
50
|
+
|
51
|
+
# Whether the given geometry is closed or not
|
52
|
+
#
|
53
|
+
# A geometry is considered closed when it's first coordinate equals the
|
54
|
+
# last coordinate.
|
55
|
+
#
|
56
|
+
# @param geometry_index [Integer] geometry to check
|
57
|
+
# @return [Boolean] true if the geometry is closed or false otherwise
|
58
|
+
def closed?(geometry_index:)
|
59
|
+
geometry = @geometries[geometry_index]
|
60
|
+
geometry.first == geometry.last
|
61
|
+
end
|
62
|
+
|
63
|
+
# Find a position on a geometry nearest to the given coordinates
|
64
|
+
#
|
65
|
+
# @param geometry_index [Integer] index of the geometry on which to search
|
66
|
+
# or +nil+ to search on all geometries
|
67
|
+
# @param xy [AIXM::XY] coordinates to approximate
|
68
|
+
# @return [AIPP::Border::Position] position nearest to the given coordinates
|
69
|
+
def nearest(geometry_index: nil, xy:)
|
70
|
+
position = nil
|
71
|
+
min_distance = 21_000_000 # max distance on earth in meters
|
72
|
+
@geometries.each.with_index do |geometry, g_index|
|
73
|
+
next unless geometry_index.nil? || geometry_index == g_index
|
74
|
+
geometry.each.with_index do |coordinates, c_index|
|
75
|
+
distance = xy.distance(coordinates).dist
|
76
|
+
if distance < min_distance
|
77
|
+
position = Position.new(geometries: geometries, geometry_index: g_index, coordinates_index: c_index)
|
78
|
+
min_distance = distance
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
position
|
83
|
+
end
|
84
|
+
|
85
|
+
# Get a segment of a geometry between the given starting and ending
|
86
|
+
# positions
|
87
|
+
#
|
88
|
+
# The segment ends either at the given ending position or at the last
|
89
|
+
# coordinates of the geometry. However, if the geometry is closed, the
|
90
|
+
# segment always continues up to the given ending position.
|
91
|
+
#
|
92
|
+
# @param from_position [AIPP::Border::Position] starting position
|
93
|
+
# @param to_position [AIPP::Border::Position] ending position
|
94
|
+
# @return [Array<AIXM::XY>] array of coordinates describing the segment
|
95
|
+
def segment(from_position:, to_position:)
|
96
|
+
fail(ArgumentError, "both positions must be on the same geometry") unless from_position.geometry_index == to_position.geometry_index
|
97
|
+
geometry_index = from_position.geometry_index
|
98
|
+
geometry = @geometries[geometry_index]
|
99
|
+
if closed?(geometry_index: geometry_index)
|
100
|
+
up = from_position.coordinates_index.upto(to_position.coordinates_index)
|
101
|
+
down = from_position.coordinates_index.downto(0) + (geometry.count - 2).downto(to_position.coordinates_index)
|
102
|
+
geometry.values_at(*(up.count < down.count ? up : down).to_a)
|
103
|
+
else
|
104
|
+
geometry.values_at(*from_position.coordinates_index.up_or_downto(to_position.coordinates_index).to_a)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def load_geometries
|
111
|
+
JSON.load(@file)['geometries'].map do |line_string|
|
112
|
+
line_string['coordinates'].map do |long, lat|
|
113
|
+
AIXM.xy(long: long, lat: lat)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Position defines an exact point on a border
|
119
|
+
#
|
120
|
+
# @example
|
121
|
+
# position = AIPP::Border::Position.new(
|
122
|
+
# geometries: border.geometries, geometry_index: 0, coordinates_index: 0
|
123
|
+
# )
|
124
|
+
# position.xy # => #<AIXM::XY 45.12013320N 006.00953165E>
|
125
|
+
class Position
|
126
|
+
attr_accessor :geometry_index
|
127
|
+
attr_accessor :coordinates_index
|
128
|
+
|
129
|
+
def initialize(geometries:, geometry_index:, coordinates_index:)
|
130
|
+
@geometries, @geometry_index, @coordinates_index = geometries, geometry_index, coordinates_index
|
131
|
+
end
|
132
|
+
|
133
|
+
# @return [String]
|
134
|
+
def inspect
|
135
|
+
%Q(#<#{self.class} xy=#{xy}>)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Coordinates for this position
|
139
|
+
#
|
140
|
+
# @return [AIXM::XY, nil] coordinates or nil if the indexes don't exist
|
141
|
+
def xy
|
142
|
+
@geometries.dig(@geometry_index, @coordinates_index)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
data/lib/aipp/downloader.rb
CHANGED
@@ -57,7 +57,7 @@ module AIPP
|
|
57
57
|
type ||= Pathname(URI(url).path).extname[1..-1].to_sym
|
58
58
|
file = work_path.join([document, type].join('.'))
|
59
59
|
unless file.exist?
|
60
|
-
|
60
|
+
verbose_info "Downloading #{document}"
|
61
61
|
IO.copy_stream(Kernel.open(url), file)
|
62
62
|
end
|
63
63
|
convert file
|
data/lib/aipp/executable.rb
CHANGED
@@ -8,7 +8,7 @@ module AIPP
|
|
8
8
|
@options = options
|
9
9
|
@options[:airac] = AIPP::AIRAC.new
|
10
10
|
@options[:storage] = Pathname(Dir.home).join('.aipp')
|
11
|
-
@options[:force] = $PRY_ON_WARN = $PRY_ON_ERROR = false
|
11
|
+
@options[:force] = $VERBOSE_INFO = $PRY_ON_WARN = $PRY_ON_ERROR = false
|
12
12
|
OptionParser.new do |o|
|
13
13
|
o.banner = <<~END
|
14
14
|
Download online AIP and convert it to #{options[:schema].upcase}.
|
@@ -19,7 +19,7 @@ module AIPP
|
|
19
19
|
o.on('-a', '--aip STRING', String, 'process this AIP only (e.g. "ENR-5.1")') { |v| @options[:aip] = v.upcase }
|
20
20
|
o.on('-s', '--storage DIR', String, 'storage directory (default: "~/.aipp")') { |v| @options[:storage] = Pathname(v) }
|
21
21
|
o.on('-f', '--[no-]force', 'ignore XML schema validation (default: false)') { |v| @options[:force] = v }
|
22
|
-
o.on('-v', '--[no-]verbose', 'verbose output
|
22
|
+
o.on('-v', '--[no-]verbose', 'verbose output (default: false)') { |v| $VERBOSE_INFO = v }
|
23
23
|
o.on('-w', '--pry-on-warn [ID]', Integer, 'open pry on warn with ID (default: nil)') { |v| $PRY_ON_WARN = v || true }
|
24
24
|
o.on('-e', '--[no-]pry-on-error', 'open pry on error (default: false)') { |v| $PRY_ON_ERROR = v }
|
25
25
|
o.on('-A', '--about', 'show author/license information and exit') { about }
|
data/lib/aipp/parser.rb
CHANGED
@@ -12,6 +12,9 @@ module AIPP
|
|
12
12
|
# @return [AIXM::Document] target document
|
13
13
|
attr_reader :aixm
|
14
14
|
|
15
|
+
# @return [Hash] map from border names to border objects
|
16
|
+
attr_reader :borders
|
17
|
+
|
15
18
|
# @return [OpenStruct] object cache
|
16
19
|
attr_reader :cache
|
17
20
|
|
@@ -22,6 +25,7 @@ module AIPP
|
|
22
25
|
@config = {}
|
23
26
|
@aixm = AIXM.document(region: @options[:region], effective_at: @options[:airac].date)
|
24
27
|
@dependencies = THash.new
|
28
|
+
@borders = {}
|
25
29
|
@cache = OpenStruct.new
|
26
30
|
end
|
27
31
|
|
@@ -38,9 +42,16 @@ module AIPP
|
|
38
42
|
info("Reading region #{options[:region]}")
|
39
43
|
dir = Pathname(__FILE__).dirname.join('regions', options[:region])
|
40
44
|
fail("unknown region `#{options[:region]}'") unless dir.exist?
|
45
|
+
# Borders
|
46
|
+
dir.glob('borders/*.geojson').each do |file|
|
47
|
+
border = AIPP::Border.new(file)
|
48
|
+
@borders[border.name] = border
|
49
|
+
end
|
50
|
+
# Helpers
|
41
51
|
dir.glob('helpers/*.rb').each { |f| require f }
|
52
|
+
# Parsers
|
42
53
|
dir.glob('*.rb').each do |file|
|
43
|
-
|
54
|
+
verbose_info "Requiring #{file.basename}"
|
44
55
|
require file
|
45
56
|
aip = file.basename('.*').to_s
|
46
57
|
@dependencies[aip] = ("AIPP::%s::%s::DEPENDS" % [options[:region], aip.remove(/\W/).classify]).constantize
|
data/lib/aipp/patcher.rb
CHANGED
@@ -24,7 +24,7 @@ module AIPP
|
|
24
24
|
define_method(:"#{attribute}=") do |value|
|
25
25
|
catch :abort do
|
26
26
|
value = block.call(parser, self, value)
|
27
|
-
|
27
|
+
verbose_info("PATCH: #{self.inspect}", color: :magenta)
|
28
28
|
end
|
29
29
|
send(:"original_#{attribute}=", value)
|
30
30
|
end
|
data/lib/aipp/pdf.rb
CHANGED
@@ -97,13 +97,13 @@ module AIPP
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def read_cache
|
100
|
-
cache_file = "#{@file}.json"
|
101
|
-
if
|
102
|
-
JSON.load
|
100
|
+
cache_file = Pathname.new("#{@file}.json")
|
101
|
+
if cache_file.exist? && (@file.stat.mtime - cache_file.stat.mtime).abs < 1
|
102
|
+
JSON.load cache_file
|
103
103
|
else
|
104
104
|
read.tap do |data|
|
105
|
-
|
106
|
-
FileUtils.touch(cache_file, mtime:
|
105
|
+
cache_file.write data.to_json
|
106
|
+
FileUtils.touch(cache_file, mtime: @file.stat.mtime)
|
107
107
|
end
|
108
108
|
end
|
109
109
|
end
|
@@ -32,9 +32,9 @@ module AIPP
|
|
32
32
|
tbody = prepare(html: read).css('tbody').first # skip altiports
|
33
33
|
tbody.css('tr').to_enum.with_index(1).each do |tr, index|
|
34
34
|
if tr.attr(:id).match?(/-TXT_NAME-/)
|
35
|
-
|
35
|
+
add @airport if @airport && !ad2_exists
|
36
36
|
@airport = airport_from tr
|
37
|
-
|
37
|
+
verbose_info "Parsing #{@airport.id}"
|
38
38
|
ad2_exists = false
|
39
39
|
if airport = select(:airport, id: @airport.id).first
|
40
40
|
ad2_exists = true
|
@@ -47,7 +47,7 @@ module AIPP
|
|
47
47
|
rescue => error
|
48
48
|
warn("error parsing #{@airport.id} at ##{index}: #{error.message}", pry: error)
|
49
49
|
end
|
50
|
-
|
50
|
+
add @airport if @airport && !ad2_exists
|
51
51
|
end
|
52
52
|
|
53
53
|
private
|
@@ -64,7 +64,7 @@ module AIPP
|
|
64
64
|
).tap do |airport|
|
65
65
|
airport.z = AIXM.z(tds[4].text.strip.to_i, :qnh)
|
66
66
|
airport.declination = tds[2].text.remove('°').strip.to_f
|
67
|
-
|
67
|
+
# airport.transition_z = AIXM.z(5000, :qnh) # TODO: default - exceptions exist
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|