aipp 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.ruby-version +1 -1
- data/.yardopts +3 -0
- data/CHANGELOG.md +25 -10
- data/README.md +116 -27
- data/aipp.gemspec +4 -2
- data/exe/aip2aixm +1 -50
- data/exe/aip2ofmx +11 -0
- data/lib/aipp.rb +20 -3
- data/lib/aipp/aip.rb +63 -0
- data/lib/aipp/airac.rb +17 -9
- data/lib/aipp/executable.rb +82 -0
- data/lib/aipp/parser.rb +97 -0
- data/lib/aipp/progress.rb +40 -0
- data/lib/aipp/refinements.rb +91 -28
- data/lib/aipp/regions/LF/ENR-2.1.rb +89 -0
- data/lib/aipp/regions/LF/ENR-4.1.rb +101 -0
- data/lib/aipp/regions/LF/ENR-4.3.rb +26 -0
- data/lib/aipp/regions/LF/ENR-5.1.rb +65 -0
- data/lib/aipp/regions/LF/helper.rb +177 -0
- data/lib/aipp/t_hash.rb +46 -0
- data/lib/aipp/version.rb +1 -1
- data/spec/lib/aipp/airac_spec.rb +3 -3
- data/spec/lib/aipp/refinements_spec.rb +97 -27
- data/spec/lib/aipp/t_hash_spec.rb +44 -0
- metadata +50 -14
- data/lib/aipp/loader.rb +0 -52
- data/lib/aipp/parsers/LF/AD-1.5.rb +0 -128
- data/lib/aipp/parsers/LF/ENR-4.1.rb +0 -105
- data/lib/aipp/parsers/LF/ENR-4.3.rb +0 -32
- data/lib/aipp/parsers/LF/ENR-5.1.rb +0 -134
- data/lib/aipp/parsers/LF/helpers/html.rb +0 -11
- data/lib/aipp/parsers/LF/helpers/url.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 279a7722a7ee0070603236b477cdd96bb1babfea88e8e70cce7088069683e783
|
4
|
+
data.tar.gz: cb9453b4aca266eafc8aa7ae8d949d402c42f748d2193796b160fc17c9280068
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4102f1a2c77ea39f2b3200c61d49c7dd194768944688f42d4cb0740707d431b2dc290e35a81215de0c646284a59b8ed9fee4dff15a6cb65616e70e3cf979868a
|
7
|
+
data.tar.gz: c8087248c414c41e415c1361370f5ec84116e6a11d6aa23336eceb353f9af13f72de7b8459b7d4504a44ff4bb9206c042734e18da15a02010bd8f8074ff830d5
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-2.5.
|
1
|
+
ruby-2.5.3
|
data/.yardopts
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,22 +1,37 @@
|
|
1
|
+
## 0.2.0
|
2
|
+
|
3
|
+
#### Changes
|
4
|
+
* Complete rewrite of the framework in order to allow cross-AIP parsing made necessary due to recent changes in LF AIP.
|
5
|
+
|
6
|
+
#### Additions
|
7
|
+
* LF/ENR-2.1
|
8
|
+
* Handling of errors and warnings optimized for parser development
|
9
|
+
|
10
|
+
#### Removals
|
11
|
+
* LF/AD-1.5
|
12
|
+
|
1
13
|
## 0.1.3
|
2
14
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
15
|
+
#### Changes
|
16
|
+
* Summary at end of run
|
17
|
+
|
18
|
+
#### Additions
|
19
|
+
* LF/AD-1.5
|
20
|
+
* Source file line number evaluation
|
7
21
|
|
8
22
|
## 0.1.2
|
9
23
|
|
10
|
-
|
11
|
-
|
24
|
+
#### Additions:
|
25
|
+
* LF/ENR-4.3
|
12
26
|
|
13
27
|
## 0.1.1
|
14
28
|
|
15
|
-
|
16
|
-
|
17
|
-
|
29
|
+
#### Additions:
|
30
|
+
* LF/ENR-4.1
|
31
|
+
* Helper modules
|
18
32
|
|
19
33
|
## 0.1.0
|
20
34
|
|
21
|
-
|
35
|
+
#### Initial Implementation
|
36
|
+
* Framework and aip2aixm executable
|
22
37
|
* LF/ENR-5.1
|
data/README.md
CHANGED
@@ -8,9 +8,7 @@
|
|
8
8
|
|
9
9
|
Parser for Aeronautical Information Publication (AIP) available online.
|
10
10
|
|
11
|
-
This gem incluces
|
12
|
-
export is as [AIXM](https://github.com/svoop/aixm) which can be consumed by
|
13
|
-
[Open Flightmaps](https://openflightmaps.org).
|
11
|
+
This gem incluces two executables to download and parse aeronautical data, then export is as [AIXM](https://github.com/svoop/aixm) or [OFMX](https://github.com/openflightmaps/ofmx/wiki).
|
14
12
|
|
15
13
|
* [Homepage](https://github.com/svoop/aipp)
|
16
14
|
* Author: [Sven Schwyn - Bitcetera](http://www.bitcetera.com)
|
@@ -27,38 +25,126 @@ gem aipp
|
|
27
25
|
|
28
26
|
```
|
29
27
|
aip2aixm --help
|
28
|
+
aip2ofmx --help
|
30
29
|
```
|
31
30
|
|
32
|
-
##
|
31
|
+
## Storage
|
33
32
|
|
34
|
-
|
35
|
-
them to plug in, you have to define the following public methods:
|
33
|
+
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.
|
36
34
|
|
37
|
-
|
38
|
-
* `convert!`<br>Takes `html` ([Nokogiri document](https://github.com/sparklemotion/nokogiri)) to parse and populate `aixm` ([AIXM document](https://github.com/svoop/aixm))
|
35
|
+
## Regions
|
39
36
|
|
40
|
-
|
41
|
-
arguments:
|
37
|
+
The reference implementation is region "LF" (France).
|
42
38
|
|
43
|
-
|
44
|
-
* `@aip`
|
45
|
-
* `@airac`
|
46
|
-
* `@limit`
|
39
|
+
To implement a region, you have to create a new directory <tt>lib/aipp/regions/{REGION}</tt> and place the following files there:
|
47
40
|
|
48
|
-
|
49
|
-
|
50
|
-
`
|
41
|
+
### helper.rb
|
42
|
+
|
43
|
+
Create the file <tt>helper.rb</tt> which defines the module `AIPP::LF::Helper` and usually contains the URL builder method `url_for` used by all AIP parsers:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
module AIPP
|
47
|
+
module LF
|
48
|
+
module Helper
|
49
|
+
|
50
|
+
def url_for(aip_file)
|
51
|
+
# build and return the download URL for the aip file
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
### AIP Parsers
|
60
|
+
|
61
|
+
Say, you want to parse ENR-4.3, you have to create the file <tt>ENR-4.3.rb</tt> which defines the class `AIPP::LF::ENR43` as follows:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
module AIPP
|
65
|
+
module LF
|
66
|
+
class ENR43 < AIP
|
67
|
+
|
68
|
+
DEPENDS = %w(ENR-2.1 ENR-2.2) # declare dependencies to other AIPs
|
69
|
+
|
70
|
+
def parse
|
71
|
+
html = load_html
|
72
|
+
# read from "html" (Nokogiri::HTML::Document) and write to "aixm"
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
80
|
+
Some AIP may be split over several files which require a little more code to load the individual HTML source files:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
module AIPP
|
84
|
+
module LF
|
85
|
+
class AD2 < AIP
|
86
|
+
|
87
|
+
def parse
|
88
|
+
%i(one two three).each do |part|
|
89
|
+
html = load_html(aip_file: "#{aip}.#{part}")
|
90
|
+
# read from "html" (Nokogiri::HTML::Document) and write to "aixm"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
Inside the `parse` method, you have access to the following objects:
|
100
|
+
|
101
|
+
* `aixm` – target: instance of `AIXM::Document` (see [AIXM Rubygem](https://github.com/svoop/aixm))
|
102
|
+
* `options` – arguments read from <tt>aip2aixm</tt> or <tt>aip2ofmx</tt> respectively
|
103
|
+
* `config` – configuration read from <tt>config.yml</tt>
|
104
|
+
* `cache` – virgin `OStruct` instance to make objects available across AIPs
|
105
|
+
|
106
|
+
Furthermore, you have access to any method defined in <tt>helper.rb</tt> and you can overwrite any of them if need be (most notably `url_for`).
|
107
|
+
|
108
|
+
### Source File Line Numbers
|
109
|
+
|
110
|
+
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:
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
tr.line
|
114
|
+
```
|
115
|
+
|
116
|
+
:warning: Make sure you have build Nokogumbo `--with-libxml2`. Otherwise, all elements will report line number `0` and therefore render OFMX documents invalid. See the [Nokogumbo README](https://github.com/rubys/nokogumbo/blob/master/README.md#flavors-of-nokogumbo) for more on this.
|
117
|
+
|
118
|
+
### Errors
|
119
|
+
|
120
|
+
You should `fail` on fatal problems. The `-E` command line argument will open a Pry session when such an error occurs. Issue errors as usual:
|
51
121
|
|
52
122
|
```ruby
|
53
|
-
|
123
|
+
fail "my message"
|
54
124
|
```
|
55
125
|
|
56
|
-
|
126
|
+
### Warnings
|
127
|
+
|
128
|
+
You should `warn` on non-fatal problems. The `-W ID` command line argument will open a Pry session when then warning with the given ID occurs. To issue a warning:
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
warn("my message", context: binding) # open Pry with binding context
|
132
|
+
warn("my message", context: error) # open Pry with error context
|
133
|
+
```
|
134
|
+
|
135
|
+
### Informational Messages
|
136
|
+
|
137
|
+
You may `info` any other useful information:
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
info("my message") # show info only in verbose mode (-V)
|
141
|
+
info("my message", force: true) # always show info
|
142
|
+
info("my message", color: :green) # show info with this color
|
143
|
+
```
|
57
144
|
|
58
|
-
|
59
|
-
can be included and used in the parsers.
|
145
|
+
## AIRAC Date Calculations
|
60
146
|
|
61
|
-
|
147
|
+
The `AIPP::AIRAC` class is used to calculate AIRAC cycles:
|
62
148
|
|
63
149
|
```ruby
|
64
150
|
airac = AIPP::AIRAC.new(Date.parse('2017-12-24'))
|
@@ -70,9 +156,13 @@ airac.next_id # => 1801
|
|
70
156
|
|
71
157
|
## References
|
72
158
|
|
73
|
-
*
|
74
|
-
* [
|
75
|
-
* [
|
159
|
+
* LF - France
|
160
|
+
* [SIA – AIP publisher](https://www.sia.aviation-civile.gouv.fr)
|
161
|
+
* [OpenData – public data files](https://www.data.gouv.fr)
|
162
|
+
* [Protected Planet – protected area data files](https://www.protectedplanet.net)
|
163
|
+
* [Geo Maps – programmatically generated GeoJSON maps](https://github.com/simonepri/geo-maps)
|
164
|
+
* [Open Flightmaps – open-source aeronautical maps](https://openflightmaps.org)
|
165
|
+
* [AIXM Rubygem – AIXM/OFMX generator for Ruby](https://github.com/svoop/aixm)
|
76
166
|
|
77
167
|
## Development
|
78
168
|
|
@@ -88,8 +178,7 @@ Please submit issues on:
|
|
88
178
|
|
89
179
|
https://github.com/svoop/aipp/issues
|
90
180
|
|
91
|
-
To contribute code, fork the project on Github, add your code and submit a
|
92
|
-
pull request:
|
181
|
+
To contribute code, fork the project on Github, add your code and submit a pull request:
|
93
182
|
|
94
183
|
https://help.github.com/articles/fork-a-repo
|
95
184
|
|
data/aipp.gemspec
CHANGED
@@ -30,8 +30,10 @@ 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', '>= 0.2
|
33
|
+
spec.add_runtime_dependency 'aixm', '~> 0', '>= 0.3.2'
|
34
34
|
spec.add_runtime_dependency 'nokogiri', '~> 1'
|
35
|
-
spec.add_runtime_dependency 'nokogumbo', '~>
|
35
|
+
spec.add_runtime_dependency 'nokogumbo', '~> 2'
|
36
|
+
spec.add_runtime_dependency 'colorize', '~> 0'
|
36
37
|
spec.add_runtime_dependency 'pry', '~> 0'
|
38
|
+
spec.add_runtime_dependency 'pry-rescue', '~> 1'
|
37
39
|
end
|
data/exe/aip2aixm
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'bundler/inline'
|
4
|
-
require 'optparse'
|
5
|
-
require 'yaml'
|
6
4
|
|
7
5
|
gemfile do
|
8
6
|
source 'https://rubygems.org'
|
@@ -10,51 +8,4 @@ gemfile do
|
|
10
8
|
gem 'aipp', '~> 0'
|
11
9
|
end
|
12
10
|
|
13
|
-
|
14
|
-
attr_reader :fir, :aip, :airac, :ofm, :limit, :verbose
|
15
|
-
|
16
|
-
def initialize
|
17
|
-
@ogn = false
|
18
|
-
@airac = AIPP::AIRAC.new(Date.today).date
|
19
|
-
@limit = Float::INFINITY
|
20
|
-
@verbose = false
|
21
|
-
OptionParser.new do |o|
|
22
|
-
o.banner = <<~END
|
23
|
-
Download online AIP and convert it to AIXM for VFR.
|
24
|
-
Usage: #{File.basename($0)} [options]
|
25
|
-
END
|
26
|
-
o.on('-A', '--about', 'author and license information') { puts 'Written by Sven Schwyn (bitcetera.com) and distributed under MIT license.'; exit }
|
27
|
-
o.on('-l', '--list', "list available FIR/AIP and exit") { puts AIPP::Loader.list.to_yaml; exit }
|
28
|
-
o.on('-f', '--fir STRING', String, 'FIR (flight information region, e.g. "LF")') { |v| @fir = v }
|
29
|
-
o.on('-a', '--aip STRING', String, 'AIP (aeronautical information publication, e.g. "ENR-5.1")') { |v| @aip = v }
|
30
|
-
o.on('-d', '--airac DATE', String, 'AIRAC date (e.g. "2018-01-04", default: current)') { |v| @airac = v }
|
31
|
-
o.on('-o', '--[no-]ofm', 'Use OFM extensions (default: false)') { |v| @ofm = v }
|
32
|
-
o.on('-L', '--limit INTEGER', Integer, 'Stop conversion after this many features') { |v| @limit = v }
|
33
|
-
o.on('-D', '--[no-]debug', 'Enable debug mode (default: false)') { |v| $DEBUG = v }
|
34
|
-
o.on('-v', '--[no-]verbose', 'Verbose error reporting (default: false)') { |v| @verbose = v }
|
35
|
-
end.parse!
|
36
|
-
fail(ArgumentError, "FIR must be supplied") unless @fir
|
37
|
-
fail(ArgumentError, "AIP must be supplied") unless @aip
|
38
|
-
fail(ArgumentError, "AIRAC date must be supplied") unless @airac
|
39
|
-
end
|
40
|
-
|
41
|
-
def run
|
42
|
-
extensions = [(:ofm if ofm)].compact
|
43
|
-
filename = [fir, aip, airac].join('_') + '.aixm'
|
44
|
-
loader = AIPP::Loader.new(fir: fir, aip: aip, airac: airac, limit: limit)
|
45
|
-
File.write(Pathname.new(Dir.pwd).join(filename), loader.aixm.to_aixm(*extensions))
|
46
|
-
puts "#{loader.aixm.features.count} feature(s) written to #{filename}"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
begin
|
51
|
-
executable = Executable.new
|
52
|
-
executable.run
|
53
|
-
rescue => exception
|
54
|
-
if executable&.verbose
|
55
|
-
raise exception
|
56
|
-
else
|
57
|
-
puts "#{File.basename($0)}: #{exception.message}"
|
58
|
-
exit 1
|
59
|
-
end
|
60
|
-
end
|
11
|
+
AIPP::Executable.new(schema: File.basename($0)[4..-1].to_sym).run
|
data/exe/aip2ofmx
ADDED
data/lib/aipp.rb
CHANGED
@@ -1,12 +1,29 @@
|
|
1
|
-
require '
|
1
|
+
require 'forwardable'
|
2
|
+
require 'colorize'
|
3
|
+
require 'pry'
|
4
|
+
require 'pry-rescue'
|
5
|
+
require 'optparse'
|
6
|
+
require 'yaml'
|
2
7
|
require 'pathname'
|
3
8
|
require 'open-uri'
|
9
|
+
require 'securerandom'
|
10
|
+
require 'tsort'
|
11
|
+
require 'ostruct'
|
4
12
|
require 'date'
|
5
13
|
require 'nokogiri'
|
6
14
|
require 'nokogumbo'
|
7
15
|
require 'aixm'
|
8
16
|
|
9
17
|
require_relative 'aipp/version'
|
10
|
-
require_relative 'aipp/airac'
|
11
18
|
require_relative 'aipp/refinements'
|
12
|
-
require_relative 'aipp/
|
19
|
+
require_relative 'aipp/t_hash'
|
20
|
+
require_relative 'aipp/executable'
|
21
|
+
require_relative 'aipp/progress'
|
22
|
+
require_relative 'aipp/airac'
|
23
|
+
require_relative 'aipp/aip'
|
24
|
+
require_relative 'aipp/parser'
|
25
|
+
|
26
|
+
# Disable "did you mean?" suggestions
|
27
|
+
module DidYouMean::Correctable
|
28
|
+
remove_method :to_s
|
29
|
+
end
|
data/lib/aipp/aip.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
module AIPP
|
2
|
+
|
3
|
+
# @abstract
|
4
|
+
class AIP
|
5
|
+
using AIPP::Refinements
|
6
|
+
include AIPP::Progress
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
DEPENDS = []
|
10
|
+
|
11
|
+
# @return [String] AIP name (e.g. "ENR-2.1")
|
12
|
+
attr_reader :aip
|
13
|
+
|
14
|
+
# @return [AIXM::Document] target document
|
15
|
+
attr_reader :aixm
|
16
|
+
|
17
|
+
# @!method aixm
|
18
|
+
# @return (see AIPP::Parser#aixm)
|
19
|
+
# @!method config
|
20
|
+
# @return (see AIPP::Parser#config)
|
21
|
+
# @!method options
|
22
|
+
# @return (see AIPP::Parser#options)
|
23
|
+
# @!method cache
|
24
|
+
# @return (see AIPP::Parser#cache)
|
25
|
+
def_delegators :@parser, :aixm, :config, :options, :cache
|
26
|
+
|
27
|
+
def initialize(aip:, parser:)
|
28
|
+
@aip, @parser = aip, parser
|
29
|
+
self.class.include [:AIPP, options[:region], :Helper].constantize
|
30
|
+
end
|
31
|
+
|
32
|
+
# Load an AIP source file
|
33
|
+
#
|
34
|
+
# Depending on whether a local copy of the file exists, either:
|
35
|
+
# * download from URL to local storage and read from local storage
|
36
|
+
# * read from local storage
|
37
|
+
#
|
38
|
+
# An URL builder method +url_for(aip_file)+ must be defined either in
|
39
|
+
# +helper.rb+ or in the AIP parser definition (e.g. +ENR-2.1.rb+).
|
40
|
+
#
|
41
|
+
# @param aip_file [String] e.g. "ENR-2.1" or "AD-2.LFMV" (default: +aip+)
|
42
|
+
# @return [Nokogiri::HTML5] HTML document
|
43
|
+
def load_html(aip_file: nil)
|
44
|
+
aip_file ||= aip
|
45
|
+
unless (storage_path = storage_path(aip_file)).exist?
|
46
|
+
info("Downloading #{storage_file}", force: true)
|
47
|
+
storage_path.mkpath
|
48
|
+
IO.copy_stream(open(url_for(aip_file)), storage_path)
|
49
|
+
end
|
50
|
+
Nokogiri::HTML5(storage_path)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def storage_path(aip_file=nil)
|
56
|
+
options[:storage].
|
57
|
+
join(options[:airac].date.xmlschema).
|
58
|
+
join(("#{aip_file}.html" if aip_file).to_s)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
data/lib/aipp/airac.rb
CHANGED
@@ -1,43 +1,51 @@
|
|
1
1
|
module AIPP
|
2
2
|
|
3
|
-
|
4
|
-
#
|
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
|
5
11
|
class AIRAC
|
6
|
-
##
|
7
12
|
# First AIRAC date following the last cycle length modification
|
8
13
|
ROOT_DATE = Date.parse('2015-06-25').freeze
|
9
14
|
|
10
|
-
##
|
11
15
|
# Length of one AIRAC cycle
|
12
16
|
DAYS_PER_CYCLE = 28
|
13
17
|
|
14
|
-
|
18
|
+
# @return [Date] AIRAC effective on date
|
19
|
+
attr_reader :date
|
15
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)
|
16
25
|
def initialize(any_date = nil)
|
17
|
-
any_date
|
18
|
-
fail(ArgumentError, "argument must be of class Date") unless any_date.is_a? Date
|
26
|
+
any_date = any_date ? Date.parse(any_date.to_s) : Date.today
|
19
27
|
fail(ArgumentError, "cannot calculate dates before #{ROOT_DATE}") if any_date < ROOT_DATE
|
20
28
|
@date = date_for(any_date)
|
21
29
|
@id = id_for(@date)
|
22
30
|
end
|
23
31
|
|
32
|
+
# @return [Date] next AIRAC effective on date
|
24
33
|
def next_date
|
25
34
|
date + DAYS_PER_CYCLE
|
26
35
|
end
|
27
36
|
|
37
|
+
# @return [Integer] next AIRAC cycle ID
|
28
38
|
def next_id
|
29
39
|
id_for next_date
|
30
40
|
end
|
31
41
|
|
32
42
|
private
|
33
43
|
|
34
|
-
##
|
35
44
|
# Find the AIRAC date for +any_date+
|
36
45
|
def date_for(any_date)
|
37
46
|
ROOT_DATE + (any_date - ROOT_DATE).to_i / DAYS_PER_CYCLE * DAYS_PER_CYCLE
|
38
47
|
end
|
39
48
|
|
40
|
-
##
|
41
49
|
# Find the AIRAC ID for the AIRAC +date+
|
42
50
|
def id_for(date)
|
43
51
|
(date.year % 100) * 100 + ((date.yday - 1) / 28) + 1
|