aipp 0.1.3 → 0.2.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
- 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
|