aipp 0.2.4 → 1.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 -0
- data/CHANGELOG.md +38 -0
- data/README.md +222 -88
- data/exe/aip2aixm +2 -2
- data/exe/aip2ofmx +2 -2
- data/lib/aipp/aip.rb +113 -31
- data/lib/aipp/border.rb +77 -46
- data/lib/aipp/debugger.rb +101 -0
- data/lib/aipp/downloader.rb +39 -26
- data/lib/aipp/executable.rb +41 -22
- data/lib/aipp/parser.rb +94 -21
- data/lib/aipp/patcher.rb +5 -2
- data/lib/aipp/pdf.rb +1 -1
- data/lib/aipp/regions/LF/README.md +49 -0
- data/lib/aipp/regions/LF/aerodromes.rb +223 -0
- data/lib/aipp/regions/LF/d_p_r_airspaces.rb +56 -0
- data/lib/aipp/regions/LF/dangerous_activities.rb +49 -0
- data/lib/aipp/regions/LF/designated_points.rb +47 -0
- data/lib/aipp/regions/LF/fixtures/aerodromes.yml +608 -0
- data/lib/aipp/regions/LF/helipads.rb +122 -0
- data/lib/aipp/regions/LF/helpers/base.rb +218 -0
- data/lib/aipp/regions/LF/helpers/surface.rb +49 -0
- data/lib/aipp/regions/LF/helpers/usage_limitation.rb +20 -0
- data/lib/aipp/regions/LF/navigational_aids.rb +85 -0
- data/lib/aipp/regions/LF/obstacles.rb +153 -0
- data/lib/aipp/regions/LF/serviced_airspaces.rb +70 -0
- data/lib/aipp/regions/LF/services.rb +172 -0
- data/lib/aipp/t_hash.rb +4 -5
- data/lib/aipp/version.rb +1 -1
- data/lib/aipp.rb +11 -5
- data/lib/core_ext/enumerable.rb +9 -9
- data/lib/core_ext/hash.rb +21 -5
- data/lib/core_ext/nokogiri.rb +54 -0
- data/lib/core_ext/string.rb +38 -66
- data.tar.gz.sig +2 -0
- metadata +180 -188
- metadata.gz.sig +0 -0
- data/.gitignore +0 -8
- data/.ruby-version +0 -1
- data/.travis.yml +0 -8
- data/.yardopts +0 -3
- data/Guardfile +0 -7
- data/TODO.md +0 -6
- data/aipp.gemspec +0 -44
- data/gems.rb +0 -3
- data/lib/aipp/airac.rb +0 -55
- data/lib/aipp/regions/LF/AD-1.3.rb +0 -162
- data/lib/aipp/regions/LF/AD-1.6.rb +0 -31
- data/lib/aipp/regions/LF/AD-2.rb +0 -313
- data/lib/aipp/regions/LF/AD-3.1.rb +0 -185
- data/lib/aipp/regions/LF/ENR-2.1.rb +0 -92
- data/lib/aipp/regions/LF/ENR-4.1.rb +0 -97
- data/lib/aipp/regions/LF/ENR-4.3.rb +0 -28
- data/lib/aipp/regions/LF/ENR-5.1.rb +0 -75
- data/lib/aipp/regions/LF/ENR-5.5.rb +0 -53
- data/lib/aipp/regions/LF/fixtures/AD-1.3.yml +0 -511
- data/lib/aipp/regions/LF/fixtures/AD-2.yml +0 -185
- data/lib/aipp/regions/LF/fixtures/AD-3.1.yml +0 -10
- data/lib/aipp/regions/LF/helpers/AD_radio.rb +0 -90
- data/lib/aipp/regions/LF/helpers/URL.rb +0 -26
- data/lib/aipp/regions/LF/helpers/common.rb +0 -217
- data/lib/core_ext/object.rb +0 -43
- data/rakefile.rb +0 -12
- data/spec/fixtures/archive.zip +0 -0
- data/spec/fixtures/border.geojson +0 -201
- data/spec/fixtures/document.pdf +0 -0
- data/spec/fixtures/document.pdf.json +0 -1
- data/spec/fixtures/new.html +0 -6
- data/spec/fixtures/new.pdf +0 -0
- data/spec/fixtures/new.txt +0 -1
- data/spec/lib/aipp/airac_spec.rb +0 -98
- data/spec/lib/aipp/border_spec.rb +0 -135
- data/spec/lib/aipp/downloader_spec.rb +0 -81
- data/spec/lib/aipp/patcher_spec.rb +0 -46
- data/spec/lib/aipp/pdf_spec.rb +0 -124
- data/spec/lib/aipp/t_hash_spec.rb +0 -44
- data/spec/lib/aipp/version_spec.rb +0 -7
- data/spec/lib/core_ext/enumberable_spec.rb +0 -76
- data/spec/lib/core_ext/hash_spec.rb +0 -27
- data/spec/lib/core_ext/integer_spec.rb +0 -15
- data/spec/lib/core_ext/nil_class_spec.rb +0 -11
- data/spec/lib/core_ext/string_spec.rb +0 -112
- data/spec/sounds/failure.mp3 +0 -0
- data/spec/sounds/success.mp3 +0 -0
- data/spec/spec_helper.rb +0 -28
data/spec/lib/aipp/airac_spec.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
require_relative '../../spec_helper'
|
2
|
-
|
3
|
-
describe AIPP::AIRAC do
|
4
|
-
describe :initialize do
|
5
|
-
it "won't accept invalid arguments" do
|
6
|
-
-> { AIPP::AIRAC.new(0) }.must_raise ArgumentError
|
7
|
-
-> { AIPP::AIRAC.new(AIPP::AIRAC::ROOT_DATE - 1) }.must_raise ArgumentError
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
context "on AIRAC date (as Date)" do
|
12
|
-
subject do
|
13
|
-
AIPP::AIRAC.new(Date.parse('2018-01-04'))
|
14
|
-
end
|
15
|
-
|
16
|
-
it "must calculate correct #date" do
|
17
|
-
subject.date.must_equal Date.parse('2018-01-04')
|
18
|
-
end
|
19
|
-
|
20
|
-
it "must calculate correct #id" do
|
21
|
-
subject.id.must_equal 1801
|
22
|
-
end
|
23
|
-
|
24
|
-
it "must calculate correct #next_date" do
|
25
|
-
subject.next_date.must_equal Date.parse('2018-02-01')
|
26
|
-
end
|
27
|
-
|
28
|
-
it "must calculate correct #next_id" do
|
29
|
-
subject.next_id.must_equal 1802
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
context "one day before AIRAC date (as String)" do
|
34
|
-
subject do
|
35
|
-
AIPP::AIRAC.new('2018-01-03')
|
36
|
-
end
|
37
|
-
|
38
|
-
it "must calculate correct #date" do
|
39
|
-
subject.date.must_equal Date.parse('2017-12-07')
|
40
|
-
end
|
41
|
-
|
42
|
-
it "must calculate correct #id" do
|
43
|
-
subject.id.must_equal 1713
|
44
|
-
end
|
45
|
-
|
46
|
-
it "must calculate correct #next_date" do
|
47
|
-
subject.next_date.must_equal Date.parse('2018-01-04')
|
48
|
-
end
|
49
|
-
|
50
|
-
it "must calculate correct #next_id" do
|
51
|
-
subject.next_id.must_equal 1801
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
context "one day after AIRAC date" do
|
56
|
-
subject do
|
57
|
-
AIPP::AIRAC.new(Date.parse('2018-01-05'))
|
58
|
-
end
|
59
|
-
|
60
|
-
it "must calculate correct #date" do
|
61
|
-
subject.date.must_equal Date.parse('2018-01-04')
|
62
|
-
end
|
63
|
-
|
64
|
-
it "must calculate correct #id" do
|
65
|
-
subject.id.must_equal 1801
|
66
|
-
end
|
67
|
-
|
68
|
-
it "must calculate correct #next_date" do
|
69
|
-
subject.next_date.must_equal Date.parse('2018-02-01')
|
70
|
-
end
|
71
|
-
|
72
|
-
it "must calculate correct #next_id" do
|
73
|
-
subject.next_id.must_equal 1802
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
context "end of year with 14 AIRAC cycles" do
|
78
|
-
subject do
|
79
|
-
AIPP::AIRAC.new(Date.parse('2020-12-31'))
|
80
|
-
end
|
81
|
-
|
82
|
-
it "must calculate correct #date" do
|
83
|
-
subject.date.must_equal Date.parse('2020-12-31')
|
84
|
-
end
|
85
|
-
|
86
|
-
it "must calculate correct #id" do
|
87
|
-
subject.id.must_equal 2014
|
88
|
-
end
|
89
|
-
|
90
|
-
it "must calculate correct #next_date" do
|
91
|
-
subject.next_date.must_equal Date.parse('2021-01-28')
|
92
|
-
end
|
93
|
-
|
94
|
-
it "must calculate correct #next_id" do
|
95
|
-
subject.next_id.must_equal 2101
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
@@ -1,135 +0,0 @@
|
|
1
|
-
require_relative '../../spec_helper'
|
2
|
-
|
3
|
-
describe AIPP::Border::Position do
|
4
|
-
subject do
|
5
|
-
AIPP::Border::Position.new(
|
6
|
-
geometries: [
|
7
|
-
[AIXM.xy(long: 0, lat: 0), AIXM.xy(long: 1, lat: 1), AIXM.xy(long: 2, lat: 2)],
|
8
|
-
[AIXM.xy(long: 10, lat: 10), AIXM.xy(long: 11, lat: 11), AIXM.xy(long: 12, lat: 12)]
|
9
|
-
],
|
10
|
-
geometry_index: 0,
|
11
|
-
coordinates_index: 0
|
12
|
-
)
|
13
|
-
end
|
14
|
-
|
15
|
-
describe :xy do
|
16
|
-
it "returns the coordinates" do
|
17
|
-
subject.xy.must_equal AIXM.xy(long: 0, lat: 0)
|
18
|
-
end
|
19
|
-
|
20
|
-
it "returns nil if the geometry index is out of bounds" do
|
21
|
-
subject.tap { |s| s.geometry_index = 2 }.xy.must_be_nil
|
22
|
-
end
|
23
|
-
|
24
|
-
it "returns nil if the coordinates index is out of bounds" do
|
25
|
-
subject.tap { |s| s.coordinates_index = 3 }.xy.must_be_nil
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
describe AIPP::Border do
|
31
|
-
let :fixtures_dir do
|
32
|
-
Pathname(__FILE__).join('..', '..', '..', 'fixtures')
|
33
|
-
end
|
34
|
-
|
35
|
-
# The border.geojson fixture defines three geometries:
|
36
|
-
# * index 0: closed geometry circumventing the airfield of Pujaut
|
37
|
-
# * index 1: closed geometry circumventing the village of Pujaut
|
38
|
-
# * index 2: unclosed I-shaped geometry following the TGV from the S to N bridges over the Rhône
|
39
|
-
# * index 3: unclosed U-shaped geometry around Île de Bartelasse from N to S end of Pont Daladier
|
40
|
-
subject do
|
41
|
-
AIPP::Border.new(fixtures_dir.join('border.geojson'))
|
42
|
-
end
|
43
|
-
|
44
|
-
describe :initialize do
|
45
|
-
it "fails for files unless the extension is .geojson" do
|
46
|
-
-> { AIPP::Border.new("/path/to/another.txt") }.must_raise ArgumentError
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
describe :name do
|
51
|
-
it "returns the upcased file name" do
|
52
|
-
subject.name.must_equal 'BORDER'
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
describe :closed? do
|
57
|
-
it "returns true for closed geometries" do
|
58
|
-
subject.closed?(geometry_index: 0).must_equal true
|
59
|
-
subject.closed?(geometry_index: 1).must_equal true
|
60
|
-
end
|
61
|
-
|
62
|
-
it "returns false for unclosed geometries" do
|
63
|
-
subject.closed?(geometry_index: 2).must_equal false
|
64
|
-
subject.closed?(geometry_index: 3).must_equal false
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
describe :nearest do
|
69
|
-
let :point do
|
70
|
-
AIXM.xy(lat: 44.008187986625636, long: 4.759397506713866)
|
71
|
-
end
|
72
|
-
|
73
|
-
it "finds the nearest position on any geometry" do
|
74
|
-
position = subject.nearest(xy: point)
|
75
|
-
position.geometry_index.must_equal 1
|
76
|
-
position.coordinates_index.must_equal 12
|
77
|
-
position.xy.must_equal AIXM.xy(lat: 44.01065725159039, long: 4.760427474975586)
|
78
|
-
end
|
79
|
-
|
80
|
-
it "finds the nearest postition on a given geometry" do
|
81
|
-
position = subject.nearest(xy: point, geometry_index: 0)
|
82
|
-
position.geometry_index.must_equal 0
|
83
|
-
position.coordinates_index.must_equal 2
|
84
|
-
position.xy.must_equal AIXM.xy(lat: 44.00269350325321, long: 4.7519731521606445)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
describe :segment do
|
89
|
-
it "fails if positions are not on the same geometry" do
|
90
|
-
from_position = AIPP::Border::Position.new(geometries: subject.geometries, geometry_index: 0, coordinates_index: 0)
|
91
|
-
to_position = AIPP::Border::Position.new(geometries: subject.geometries, geometry_index: 1, coordinates_index: 0)
|
92
|
-
-> { subject.segment(from_position: from_position, to_position: to_position) }.must_raise ArgumentError
|
93
|
-
end
|
94
|
-
|
95
|
-
it "returns shortest segment on an unclosed I-shaped geometry" do
|
96
|
-
from_position = subject.nearest(xy: AIXM.xy(lat: 44.002940457248556, long: 4.734249114990234))
|
97
|
-
to_position = subject.nearest(xy: AIXM.xy(lat: 44.07155380033749, long: 4.7687530517578125), geometry_index: from_position.geometry_index)
|
98
|
-
subject.segment(from_position: from_position, to_position: to_position).must_equal [
|
99
|
-
AIXM.xy(lat: 44.00516299694704, long: 4.7371673583984375),
|
100
|
-
AIXM.xy(lat: 44.02195282780904, long: 4.743347167968749),
|
101
|
-
AIXM.xy(lat: 44.037503870182896, long: 4.749870300292969),
|
102
|
-
AIXM.xy(lat: 44.05379106204314, long: 4.755706787109375),
|
103
|
-
AIXM.xy(lat: 44.070073775703484, long: 4.7646331787109375)
|
104
|
-
]
|
105
|
-
end
|
106
|
-
|
107
|
-
it "returns shortest segment on an unclosed U-shaped geometry" do
|
108
|
-
from_position = subject.nearest(xy: AIXM.xy(lat: 43.96563876212758, long: 4.8126983642578125))
|
109
|
-
to_position = subject.nearest(xy: AIXM.xy(lat: 43.956989327857265, long: 4.83123779296875), geometry_index: from_position.geometry_index)
|
110
|
-
subject.segment(from_position: from_position, to_position: to_position).must_equal [
|
111
|
-
AIXM.xy(lat: 43.9646503190861, long: 4.815788269042969),
|
112
|
-
AIXM.xy(lat: 43.98614524381678, long: 4.82025146484375),
|
113
|
-
AIXM.xy(lat: 43.98491011404692, long: 4.840850830078125),
|
114
|
-
AIXM.xy(lat: 43.99479043262446, long: 4.845314025878906),
|
115
|
-
AIXM.xy(lat: 43.98367495857784, long: 4.8538970947265625),
|
116
|
-
AIXM.xy(lat: 43.967121395851485, long: 4.851493835449218),
|
117
|
-
AIXM.xy(lat: 43.96069638244953, long: 4.8442840576171875),
|
118
|
-
AIXM.xy(lat: 43.96069638244953, long: 4.829521179199219)
|
119
|
-
]
|
120
|
-
end
|
121
|
-
|
122
|
-
it "returns shortest segment ignoring endings on a closed geometry" do
|
123
|
-
from_position = subject.nearest(xy: AIXM.xy(lat: 44.00022390676026, long: 4.789009094238281))
|
124
|
-
to_position = subject.nearest(xy: AIXM.xy(lat: 43.99800118202362, long: 4.765834808349609), geometry_index: from_position.geometry_index)
|
125
|
-
subject.segment(from_position: from_position, to_position: to_position).must_equal [
|
126
|
-
AIXM.xy(lat: 44.00077957493397, long: 4.787635803222656),
|
127
|
-
AIXM.xy(lat: 43.99818641226534, long: 4.784030914306641),
|
128
|
-
AIXM.xy(lat: 43.994111213373934, long: 4.78205680847168),
|
129
|
-
AIXM.xy(lat: 44.00115001749186, long: 4.777421951293944),
|
130
|
-
AIXM.xy(lat: 44.002940457248556, long: 4.770212173461914)
|
131
|
-
]
|
132
|
-
end
|
133
|
-
|
134
|
-
end
|
135
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
require_relative '../../spec_helper'
|
2
|
-
|
3
|
-
describe AIPP::Downloader do
|
4
|
-
let :fixtures_dir do
|
5
|
-
Pathname(__FILE__).join('..', '..', '..', 'fixtures')
|
6
|
-
end
|
7
|
-
|
8
|
-
let :tmp_dir do
|
9
|
-
Pathname(Dir.mktmpdir).tap do |tmp_dir|
|
10
|
-
(archives_dir = tmp_dir.join('archives')).mkpath
|
11
|
-
FileUtils.cp(fixtures_dir.join('archive.zip'), archives_dir)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
after do
|
16
|
-
FileUtils.rm_rf(tmp_dir)
|
17
|
-
end
|
18
|
-
|
19
|
-
describe :read do
|
20
|
-
context "archive does not exist" do
|
21
|
-
it "creates the archive" do
|
22
|
-
Spy.on(Kernel, open: File.open(fixtures_dir.join('new.html')))
|
23
|
-
subject = AIPP::Downloader.new(storage: tmp_dir, archive: 'new-archive') do |downloader|
|
24
|
-
File.exist?(tmp_dir.join('work')).must_equal true
|
25
|
-
downloader.read(document: 'new', url: 'http://localhost/new.html')
|
26
|
-
end
|
27
|
-
zip_entries(subject.archive_file).must_equal %w(new.html)
|
28
|
-
subject.send(:archives_path).children.count.must_equal 2
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
context "archive does exist" do
|
33
|
-
it "unzips and uses the archive" do
|
34
|
-
Spy.on(Kernel, open: File.open(fixtures_dir.join('new.html')))
|
35
|
-
subject = AIPP::Downloader.new(storage: tmp_dir, archive: 'archive') do |downloader|
|
36
|
-
File.exist?(tmp_dir.join('work')).must_equal true
|
37
|
-
downloader.read(document: 'new', url: 'http://localhost/new.html').tap do |content|
|
38
|
-
content.must_be_instance_of Nokogiri::HTML5::Document
|
39
|
-
content.text.must_match /fixture-html-new/
|
40
|
-
end
|
41
|
-
end
|
42
|
-
zip_entries(subject.archive_file).must_equal %w(new.html one.html two.html)
|
43
|
-
subject.send(:archives_path).children.count.must_equal 1
|
44
|
-
end
|
45
|
-
|
46
|
-
it "downloads HTML documents to Nokogiri::HTML5::Document" do
|
47
|
-
Spy.on(Kernel, open: File.open(fixtures_dir.join('new.html')))
|
48
|
-
AIPP::Downloader.new(storage: tmp_dir, archive: 'archive') do |downloader|
|
49
|
-
downloader.read(document: 'new', url: 'http://localhost/new.html').tap do |content|
|
50
|
-
content.must_be_instance_of Nokogiri::HTML5::Document
|
51
|
-
content.text.must_match /fixture-html-new/
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
it "downloads and caches PDF documents to AIPP::PDF" do
|
57
|
-
Spy.on(Kernel, open: File.open(fixtures_dir.join('new.pdf')))
|
58
|
-
AIPP::Downloader.new(storage: tmp_dir, archive: 'archive') do |downloader|
|
59
|
-
downloader.read(document: 'new', url: 'http://localhost/new.pdf').tap do |content|
|
60
|
-
content.must_be_instance_of AIPP::PDF
|
61
|
-
content.text.must_match /fixture-pdf-new/
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
it "downloads explicitly specified type" do
|
67
|
-
Spy.on(Kernel, open: File.open(fixtures_dir.join('new.pdf')))
|
68
|
-
AIPP::Downloader.new(storage: tmp_dir, archive: 'archive') do |downloader|
|
69
|
-
downloader.read(document: 'new', url: 'http://localhost/new', type: :pdf).tap do |content|
|
70
|
-
content.must_be_instance_of AIPP::PDF
|
71
|
-
content.text.must_match /fixture-pdf-new/
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def zip_entries(zip_file)
|
79
|
-
Zip::File.open(zip_file).entries.map(&:name).sort
|
80
|
-
end
|
81
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
require_relative '../../spec_helper'
|
2
|
-
|
3
|
-
class Shoe
|
4
|
-
include AIPP::Patcher
|
5
|
-
|
6
|
-
attr_accessor :size
|
7
|
-
|
8
|
-
patch Shoe, :size do |parser, object, value|
|
9
|
-
case value
|
10
|
-
when 'S' then 36
|
11
|
-
when 'one-size-fits-all' then nil
|
12
|
-
else throw(:abort)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
describe AIPP::Patcher do
|
18
|
-
subject do
|
19
|
-
Shoe.new.attach_patches
|
20
|
-
end
|
21
|
-
|
22
|
-
context "with patches attached" do
|
23
|
-
after do
|
24
|
-
subject.detach_patches
|
25
|
-
end
|
26
|
-
|
27
|
-
it "overwrites with non-nil values" do
|
28
|
-
subject.tap { |s| s.size = 'S' }.size.must_equal 36
|
29
|
-
end
|
30
|
-
|
31
|
-
it "overwrite with nil values" do
|
32
|
-
subject.tap { |s| s.size = 'one-size-fits-all' }.size.must_be_nil
|
33
|
-
end
|
34
|
-
|
35
|
-
it "skips overwrite if abort is thrown" do
|
36
|
-
subject.tap { |s| s.size = 42 }.size.must_equal 42
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
context "with patches detached" do
|
41
|
-
it "removes patches" do
|
42
|
-
subject.detach_patches
|
43
|
-
subject.tap { |s| s.size = 'S' }.size.must_equal 'S'
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
data/spec/lib/aipp/pdf_spec.rb
DELETED
@@ -1,124 +0,0 @@
|
|
1
|
-
require_relative '../../spec_helper'
|
2
|
-
|
3
|
-
describe AIPP::PDF do
|
4
|
-
let :fixtures_dir do
|
5
|
-
Pathname(__FILE__).join('..', '..', '..', 'fixtures')
|
6
|
-
end
|
7
|
-
|
8
|
-
subject do
|
9
|
-
AIPP::PDF.new(fixtures_dir.join('document.pdf'))
|
10
|
-
end
|
11
|
-
|
12
|
-
describe :@page_ranges do
|
13
|
-
it "returns an array of page end positions" do
|
14
|
-
subject.instance_variable_get(:@page_ranges).must_equal [74, 149, 225]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
describe :page_for do
|
19
|
-
it "finds the page for any given position" do
|
20
|
-
subject.send(:page_for, index: 0).must_equal 1
|
21
|
-
subject.send(:page_for, index: 50).must_equal 1
|
22
|
-
subject.send(:page_for, index: 74).must_equal 1
|
23
|
-
subject.send(:page_for, index: 75).must_equal 2
|
24
|
-
subject.send(:page_for, index: 149).must_equal 2
|
25
|
-
subject.send(:page_for, index: 150).must_equal 3
|
26
|
-
subject.send(:page_for, index: 223).must_equal 3
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
describe :from do
|
31
|
-
it "fences beginning to any position" do
|
32
|
-
subject.from(100).range.must_equal (100..223)
|
33
|
-
end
|
34
|
-
|
35
|
-
it "fences beginning to first existing position" do
|
36
|
-
subject.from(:begin).range.must_equal (0..223)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
describe :to do
|
41
|
-
it "fences beginning to any position" do
|
42
|
-
subject.to(100).range.must_equal (0..100)
|
43
|
-
end
|
44
|
-
|
45
|
-
it "fences beginning to first existing position" do
|
46
|
-
subject.to(:end).range.must_equal (0..223)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
context "without boundaries" do
|
51
|
-
describe :text do
|
52
|
-
it "returns the entire text" do
|
53
|
-
subject.text.must_match /\Apage 1, line 1/
|
54
|
-
subject.text.must_match /page 3, line 5\z/
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
describe :each_line do
|
59
|
-
it "maps lines to positions" do
|
60
|
-
target = [
|
61
|
-
["page 1, line 1\n", 1, false],
|
62
|
-
["page 1, line 2\n", 1, false],
|
63
|
-
["page 1, line 3\n", 1, false],
|
64
|
-
["page 1, line 4\n", 1, false],
|
65
|
-
["page 1, line 5\f", 1, false],
|
66
|
-
["page 2, line 1\n", 2, false],
|
67
|
-
["page 2, line 2\n", 2, false],
|
68
|
-
["page 2, line 3\n", 2, false],
|
69
|
-
["page 2, line 4\n", 2, false],
|
70
|
-
["page 2, line 5\f", 2, false],
|
71
|
-
["page 3, line 1\n", 3, false],
|
72
|
-
["page 3, line 2\n", 3, false],
|
73
|
-
["page 3, line 3\n", 3, false],
|
74
|
-
["page 3, line 4\n", 3, false],
|
75
|
-
["page 3, line 5", 3, true]
|
76
|
-
]
|
77
|
-
subject.each_line do |line, page, last|
|
78
|
-
target_line, target_page, target_last = target.shift
|
79
|
-
line.must_equal target_line
|
80
|
-
page.must_equal target_page
|
81
|
-
last.must_equal target_last
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
it "returns an enumerator if no block is given" do
|
86
|
-
subject.each_line.must_be_instance_of Enumerator
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
context "with boundaries" do
|
92
|
-
before do
|
93
|
-
subject.from(100).to(200)
|
94
|
-
end
|
95
|
-
|
96
|
-
describe :text do
|
97
|
-
it "returns the entire text" do
|
98
|
-
subject.text.must_match /\Ane 2/
|
99
|
-
subject.text.must_match /page 3\z/
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
describe :each_line do
|
104
|
-
it "maps lines to positions" do
|
105
|
-
target = [
|
106
|
-
["ne 2\n", 2, false],
|
107
|
-
["page 2, line 3\n", 2, false],
|
108
|
-
["page 2, line 4\n", 2, false],
|
109
|
-
["page 2, line 5\f", 2, false],
|
110
|
-
["page 3, line 1\n", 3, false],
|
111
|
-
["page 3, line 2\n", 3, false],
|
112
|
-
["page 3, line 3\n", 3, false],
|
113
|
-
["page 3", 3, true]
|
114
|
-
]
|
115
|
-
subject.each_line do |line, page, last|
|
116
|
-
target_line, target_page, target_last = target.shift
|
117
|
-
line.must_equal target_line
|
118
|
-
page.must_equal target_page
|
119
|
-
last.must_equal target_last
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require_relative '../../spec_helper'
|
2
|
-
|
3
|
-
describe AIPP::THash do
|
4
|
-
context "non-circular dependencies" do
|
5
|
-
subject do
|
6
|
-
AIPP::THash[
|
7
|
-
dns: %i(net),
|
8
|
-
webserver: %i(dns logger),
|
9
|
-
net: [],
|
10
|
-
logger: []
|
11
|
-
]
|
12
|
-
end
|
13
|
-
|
14
|
-
describe :tsort do
|
15
|
-
it "must compile the overall dependency list" do
|
16
|
-
subject.tsort.must_equal %i(net dns logger webserver)
|
17
|
-
end
|
18
|
-
|
19
|
-
it "must compile partial dependency lists" do
|
20
|
-
subject.tsort(:dns).must_equal %i(net dns)
|
21
|
-
subject.tsort(:logger).must_equal %i(logger)
|
22
|
-
subject.tsort(:webserver).must_equal %i(net dns logger webserver)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
context "circular dependencies" do
|
28
|
-
subject do
|
29
|
-
AIPP::THash[
|
30
|
-
dns: %i(net),
|
31
|
-
webserver: %i(dns logger),
|
32
|
-
net: %i(dns),
|
33
|
-
logger: []
|
34
|
-
]
|
35
|
-
end
|
36
|
-
|
37
|
-
describe :tsort do
|
38
|
-
it "must raise cyclic dependency error" do
|
39
|
-
-> { subject.tsort }.must_raise TSort::Cyclic
|
40
|
-
-> { subject.tsort(:dns) }.must_raise TSort::Cyclic
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,76 +0,0 @@
|
|
1
|
-
require_relative '../../spec_helper'
|
2
|
-
|
3
|
-
describe Enumerable do
|
4
|
-
|
5
|
-
describe :split do
|
6
|
-
context "by object" do
|
7
|
-
it "must split at matching element" do
|
8
|
-
[1, 2, 0, 3, 4].split(0).must_equal [[1, 2], [3, 4]]
|
9
|
-
end
|
10
|
-
|
11
|
-
it "won't split when no element matches" do
|
12
|
-
[1, 2, 3].split(0).must_equal [[1, 2, 3]]
|
13
|
-
end
|
14
|
-
|
15
|
-
it "won't split zero length enumerable" do
|
16
|
-
[].split(0).must_equal []
|
17
|
-
end
|
18
|
-
|
19
|
-
it "must keep leading empty subarrays" do
|
20
|
-
[0, 1, 2, 0, 3, 4].split(0).must_equal [[], [1, 2], [3, 4]]
|
21
|
-
end
|
22
|
-
|
23
|
-
it "must keep empty subarrays in the middle" do
|
24
|
-
[1, 2, 0, 0, 3, 4].split(0).must_equal [[1, 2], [], [3, 4]]
|
25
|
-
end
|
26
|
-
|
27
|
-
it "must drop trailing empty subarrays" do
|
28
|
-
[1, 2, 0, 3, 4, 0].split(0).must_equal [[1, 2], [3, 4]]
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
context "by block" do
|
33
|
-
it "must split at matching element" do
|
34
|
-
[1, 2, 0, 3, 4].split { |e| e.zero? }.must_equal [[1, 2], [3, 4]]
|
35
|
-
end
|
36
|
-
|
37
|
-
it "won't split when no element matches" do
|
38
|
-
[1, 2, 3].split { |e| e.zero? }.must_equal [[1, 2, 3]]
|
39
|
-
end
|
40
|
-
|
41
|
-
it "won't split zero length enumerable" do
|
42
|
-
[].split { |e| e.zero? }.must_equal []
|
43
|
-
end
|
44
|
-
|
45
|
-
it "must keep leading empty subarrays" do
|
46
|
-
[0, 1, 2, 0, 3, 4].split { |e| e.zero? }.must_equal [[], [1, 2], [3, 4]]
|
47
|
-
end
|
48
|
-
|
49
|
-
it "must keep empty subarrays in the middle" do
|
50
|
-
[1, 2, 0, 0, 3, 4].split { |e| e.zero? }.must_equal [[1, 2], [], [3, 4]]
|
51
|
-
end
|
52
|
-
|
53
|
-
it "must drop trailing empty subarrays" do
|
54
|
-
[1, 2, 0, 3, 4, 0].split { |e| e.zero? }.must_equal [[1, 2], [3, 4]]
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
describe :group_by_chunks do
|
60
|
-
it "fails to group if the first element does not meet the chunk condition" do
|
61
|
-
subject = [10, 11, 12, 2, 20, 21 ]
|
62
|
-
-> { subject.group_by_chunks { |i| i < 10 } }.must_raise ArgumentError
|
63
|
-
end
|
64
|
-
|
65
|
-
it "must map matching elements to array of subsequent non-matching elements" do
|
66
|
-
subject = [1, 10, 11, 12, 2, 20, 21, 3, 30, 31, 32]
|
67
|
-
subject.group_by_chunks { |i| i < 10 }.must_equal(1 => [10, 11, 12], 2 => [20, 21], 3 => [30, 31, 32])
|
68
|
-
end
|
69
|
-
|
70
|
-
it "must map matching elements to empty array if no subsequent non-matching elements exist" do
|
71
|
-
subject = [1, 10, 11, 12, 2, 3, 30]
|
72
|
-
subject.group_by_chunks { |i| i < 10 }.must_equal(1 => [10, 11, 12], 2 => [], 3 => [30])
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
require_relative '../../spec_helper'
|
2
|
-
|
3
|
-
describe Hash do
|
4
|
-
|
5
|
-
describe :metch do
|
6
|
-
subject do
|
7
|
-
{ /aa/ => :aa, /a/ => :a, 'b' => :b }
|
8
|
-
end
|
9
|
-
|
10
|
-
it "must return value of matching regexp key" do
|
11
|
-
subject.metch('abc').must_equal :a
|
12
|
-
end
|
13
|
-
|
14
|
-
it "must return value of equal non-regexp key" do
|
15
|
-
subject.metch('b').must_equal :b
|
16
|
-
end
|
17
|
-
|
18
|
-
it "fails with KeyError if nothing matches" do
|
19
|
-
-> { subject.metch('bcd') }.must_raise KeyError
|
20
|
-
end
|
21
|
-
|
22
|
-
it "returns fallback value if nothing matches" do
|
23
|
-
subject.metch('x', :foobar).must_equal :foobar
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
require_relative '../../spec_helper'
|
2
|
-
|
3
|
-
describe Integer do
|
4
|
-
|
5
|
-
describe :up_or_downto do
|
6
|
-
it "behaves like Integer#upto for an increasing range" do
|
7
|
-
10.up_or_downto(12).to_a.must_equal 10.upto(12).to_a
|
8
|
-
end
|
9
|
-
|
10
|
-
it "behaves like Integer#downto for a decreasing range" do
|
11
|
-
10.up_or_downto(8).to_a.must_equal 10.downto(8).to_a
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|