aipp 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +1 -2
- data/CHANGELOG.md +15 -0
- data/README.md +122 -37
- data/TODO.md +4 -0
- data/aipp.gemspec +8 -3
- data/lib/aipp.rb +14 -2
- data/lib/aipp/aip.rb +44 -29
- data/lib/aipp/downloader.rb +115 -0
- data/lib/aipp/executable.rb +6 -6
- data/lib/aipp/parser.rb +23 -23
- data/lib/aipp/patcher.rb +47 -0
- data/lib/aipp/pdf.rb +123 -0
- data/lib/aipp/regions/LF/AD-1.3.rb +162 -0
- data/lib/aipp/regions/LF/AD-1.3.yml +511 -0
- data/lib/aipp/regions/LF/AD-1.6.rb +31 -0
- data/lib/aipp/regions/LF/AD-2.rb +316 -0
- data/lib/aipp/regions/LF/AD-2.yml +185 -0
- data/lib/aipp/regions/LF/AD-3.1.rb-NEW +11 -0
- data/lib/aipp/regions/LF/ENR-2.1.rb +25 -24
- data/lib/aipp/regions/LF/ENR-4.1.rb +24 -23
- data/lib/aipp/regions/LF/ENR-4.3.rb +8 -6
- data/lib/aipp/regions/LF/ENR-5.1.rb +32 -22
- data/lib/aipp/regions/LF/ENR-5.5.rb-NEW +11 -0
- data/lib/aipp/regions/LF/helpers/AD_radio.rb +90 -0
- data/lib/aipp/regions/LF/helpers/URL.rb +26 -0
- data/lib/aipp/regions/LF/helpers/common.rb +186 -0
- data/lib/aipp/version.rb +1 -1
- data/lib/core_ext/enumerable.rb +52 -0
- data/lib/core_ext/nil_class.rb +10 -0
- data/lib/core_ext/object.rb +42 -0
- data/lib/core_ext/string.rb +105 -0
- data/spec/fixtures/archive.zip +0 -0
- data/spec/fixtures/document.pdf +0 -0
- data/spec/fixtures/document.pdf.json +1 -0
- data/spec/fixtures/new.html +6 -0
- data/spec/fixtures/new.pdf +0 -0
- data/spec/fixtures/new.txt +1 -0
- data/spec/lib/aipp/downloader_spec.rb +81 -0
- data/spec/lib/aipp/patcher_spec.rb +46 -0
- data/spec/lib/aipp/pdf_spec.rb +124 -0
- data/spec/lib/core_ext/enumberable_spec.rb +76 -0
- data/spec/lib/core_ext/nil_class_spec.rb +11 -0
- data/spec/lib/core_ext/string_spec.rb +88 -0
- data/spec/spec_helper.rb +1 -0
- metadata +123 -23
- data/lib/aipp/progress.rb +0 -40
- data/lib/aipp/refinements.rb +0 -114
- data/lib/aipp/regions/LF/helper.rb +0 -177
- data/spec/lib/aipp/refinements_spec.rb +0 -123
data/lib/aipp/progress.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
module AIPP
|
2
|
-
module Progress
|
3
|
-
|
4
|
-
# Issue an informational message.
|
5
|
-
#
|
6
|
-
# @param message [String] informational message
|
7
|
-
# @param force [Boolean] whether to show the message only when in verbose mode
|
8
|
-
# @param color [Symbol] override default color
|
9
|
-
def info(message, force: false, color: nil)
|
10
|
-
case
|
11
|
-
when !force && options[:verbose]
|
12
|
-
color ||= :blue
|
13
|
-
puts message.send(color)
|
14
|
-
when force
|
15
|
-
color ||= :black
|
16
|
-
puts message.send(color)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# Issue a warning and maybe open a Pry session in the context of the error
|
21
|
-
# or binding passed.
|
22
|
-
#
|
23
|
-
# @example with error context
|
24
|
-
# begin
|
25
|
-
# (...)
|
26
|
-
# rescue => error
|
27
|
-
# warn("oops", context: error)
|
28
|
-
# end
|
29
|
-
# @example with binding context
|
30
|
-
# warn("oops", context: binding)
|
31
|
-
# @param message [String] warning message
|
32
|
-
# @param context [Exception, Binding, nil] error or binding object
|
33
|
-
def warn(message, context: nil)
|
34
|
-
$WARN_COUNTER = $WARN_COUNTER.to_i + 1
|
35
|
-
Kernel.warn "WARNING #{$WARN_COUNTER}: #{message}".red
|
36
|
-
Pry::rescued(context) if context && options[:pry_on_warn] == $WARN_COUNTER
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
end
|
data/lib/aipp/refinements.rb
DELETED
@@ -1,114 +0,0 @@
|
|
1
|
-
module AIPP
|
2
|
-
module Refinements
|
3
|
-
|
4
|
-
# @!method blank_to_nil
|
5
|
-
# Convert blank strings to +nil+.
|
6
|
-
#
|
7
|
-
# @example
|
8
|
-
# "foobar".blank_to_nil # => "foobar"
|
9
|
-
# " ".blank_to_nil # => nil
|
10
|
-
# "".blank_to_nil # => nil
|
11
|
-
# nil.blank_to_nil # => nil
|
12
|
-
#
|
13
|
-
# @note This is a refinement for +String+ and +NilClass+
|
14
|
-
# @return [String, nil] converted string
|
15
|
-
refine String do
|
16
|
-
def blank_to_nil
|
17
|
-
match?(/\A\s*\z/) ? nil : self
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# Always returns +nil+, companion to +String#blank_to_nil+.
|
22
|
-
refine NilClass do
|
23
|
-
def blank_to_nil
|
24
|
-
nil
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
# @!method blank?
|
29
|
-
# Check whether the string is blank.
|
30
|
-
#
|
31
|
-
# @example
|
32
|
-
# "foobar".blank? # => false
|
33
|
-
# " ".blank? # => true
|
34
|
-
# "".blank? # => true
|
35
|
-
# nil.blank? # => true
|
36
|
-
#
|
37
|
-
# @note This is a refinement for +String+ and +NilClass+
|
38
|
-
# @return [Boolean] whether the string is blank or not
|
39
|
-
refine String do
|
40
|
-
def blank?
|
41
|
-
!blank_to_nil
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# Always returns +true+, companion to +String#blank?+.
|
46
|
-
refine NilClass do
|
47
|
-
def blank?
|
48
|
-
true
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# @!method classify
|
53
|
-
# Convert file name to class name.
|
54
|
-
#
|
55
|
-
# @example
|
56
|
-
# "ENR-5.1".classify # => "ENR51"
|
57
|
-
# "helper".classify # => "Helper"
|
58
|
-
# "foo_bar".classify # => "FooBar"
|
59
|
-
#
|
60
|
-
# @note This is a refinement for +String+
|
61
|
-
# @return [String] converted string
|
62
|
-
refine String do
|
63
|
-
def classify
|
64
|
-
gsub(/\W/, '').gsub(/(?:^|_)(\w)/) { $1.upcase }
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
# @!method constantize
|
69
|
-
# Get constant for array containing the lookup path.
|
70
|
-
#
|
71
|
-
# @example
|
72
|
-
# %w(AIPP AIRAC).constantize # => AIPP::AIRAC
|
73
|
-
#
|
74
|
-
# @note This is a refinement for +Array+
|
75
|
-
# @return [Class] converted array
|
76
|
-
refine Array do
|
77
|
-
def constantize
|
78
|
-
Kernel.const_get(self.join('::'))
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
# @!method split(object=nil, &block)
|
83
|
-
# Divides an enumerable into sub-enumerables based on a delimiter,
|
84
|
-
# returning an array of these sub-enumerables.
|
85
|
-
#
|
86
|
-
# It takes the same arguments as +Enumerable#find_index+ and suppresses
|
87
|
-
# trailing zero-length sub-enumerator as does +String#split+.
|
88
|
-
#
|
89
|
-
# @example
|
90
|
-
# [1, 2, 0, 3, 4].split { |e| e == 0 } # => [[1, 2], [3, 4]]
|
91
|
-
# [1, 2, 0, 3, 4].split(0) # => [[1, 2], [3, 4]]
|
92
|
-
# [0, 0, 1, 0, 2].split(0) # => [[], [] [1], [2]]
|
93
|
-
# [1, 0, 0, 2, 3].split(0) # => [[1], [], [2], [3]]
|
94
|
-
# [1, 0, 2, 0, 0].split(0) # => [[1], [2]]
|
95
|
-
#
|
96
|
-
# @note This is a refinement for +Enumerable+
|
97
|
-
# @param object [Object] element at which to split
|
98
|
-
# @yield [Object] element to analyze
|
99
|
-
# @yieldreturn [Boolean] whether to split at this element or not
|
100
|
-
# @return [Array]
|
101
|
-
refine Enumerable do
|
102
|
-
def split(*args, &block)
|
103
|
-
[].tap do |array|
|
104
|
-
while index = slice((start ||= 0)...length).find_index(*args, &block)
|
105
|
-
array << slice(start...start+index)
|
106
|
-
start += index + 1
|
107
|
-
end
|
108
|
-
array << slice(start..-1) if start < length
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
end
|
114
|
-
end
|
@@ -1,177 +0,0 @@
|
|
1
|
-
module AIPP
|
2
|
-
module LF
|
3
|
-
module Helper
|
4
|
-
using AIPP::Refinements
|
5
|
-
using AIXM::Refinements
|
6
|
-
|
7
|
-
BORDERS = {
|
8
|
-
'franco-allemande' => 'FRANCE_GERMANY',
|
9
|
-
'franco-espagnole' => 'FRANCE_SPAIN',
|
10
|
-
'franco-italienne' => 'FRANCE_ITALY',
|
11
|
-
'franco-suisse' => 'FRANCE_SWITZERLAND',
|
12
|
-
'franco-luxembourgeoise' => 'FRANCE_LUXEMBOURG',
|
13
|
-
'franco-belge' => 'BELGIUM_FRANCE',
|
14
|
-
'germano-suisse' => 'GERMANY_SWITZERLAND',
|
15
|
-
'hispano-andorrane' => 'ANDORRA_SPAIN',
|
16
|
-
'la côte atlantique française' => 'FRANCE_ATLANTIC_COAST',
|
17
|
-
'côte méditérrannéenne' => 'FRANCE_MEDITERRANEAN_COAST',
|
18
|
-
'limite des eaux territoriales atlantique françaises' => 'FRANCE_ATLANTIC_TERRITORIAL_SEA',
|
19
|
-
'parc national des écrins' => 'FRANCE_ECRINS_NATIONAL_PARK'
|
20
|
-
}.freeze
|
21
|
-
|
22
|
-
INTERSECTIONS = {
|
23
|
-
'FRANCE_SPAIN|ANDORRA_SPAIN' => AIXM.xy(lat: 42.502720, long: 1.725965),
|
24
|
-
'ANDORRA_SPAIN|FRANCE_SPAIN' => AIXM.xy(lat: 42.603571, long: 1.442681),
|
25
|
-
'FRANCE_SWITZERLAND|FRANCE_ITALY' => AIXM.xy(lat: 45.922701, long: 7.044125),
|
26
|
-
'BELGIUM_FRANCE|FRANCE_LUXEMBOURG' => AIXM.xy(lat: 49.546428, long: 5.818415),
|
27
|
-
'FRANCE_LUXEMBOURG|FRANCE_GERMANY' => AIXM.xy(lat: 49.469438, long: 6.367516),
|
28
|
-
'FRANCE_GERMANY|FRANCE_SWITZERLAND' => AIXM.xy(lat: 47.589831, long: 7.589049),
|
29
|
-
'GERMANY_SWITZERLAND|FRANCE_GERMANY' => AIXM.xy(lat: 47.589831, long: 7.589049)
|
30
|
-
}
|
31
|
-
|
32
|
-
ANGLICISE_MAP = {
|
33
|
-
/[^A-Z0-9 .\-]/ => '',
|
34
|
-
/ 0(\d)/ => ' \1',
|
35
|
-
/(\d)-(\d)/ => '\1.\2',
|
36
|
-
/PARTIE/ => '',
|
37
|
-
/DELEG\./ => 'DELEG ',
|
38
|
-
/FRANCAISE?/ => 'FR',
|
39
|
-
/ANGLAISE?/ => 'UK',
|
40
|
-
/BELGE/ => 'BE',
|
41
|
-
/LUXEMBOURGEOISE?/ => 'LU',
|
42
|
-
/ALLEMANDE?/ => 'DE',
|
43
|
-
/SUISSE/ => 'CH',
|
44
|
-
/ITALIEN(?:NE)?/ => 'IT',
|
45
|
-
/ESPAGNOLE?/ => 'ES',
|
46
|
-
/ANDORRANE?/ => 'AD',
|
47
|
-
/NORD/ => 'N',
|
48
|
-
/EST/ => 'E',
|
49
|
-
/SUD/ => 'S',
|
50
|
-
/OEST/ => 'W',
|
51
|
-
/ANGLO NORMANDES/ => 'ANGLO-NORMANDES',
|
52
|
-
/ +/ => ' '
|
53
|
-
}.freeze
|
54
|
-
|
55
|
-
# Download URL
|
56
|
-
|
57
|
-
def url_for(aip_file)
|
58
|
-
"https://www.sia.aviation-civile.gouv.fr/dvd/eAIP_%s/FRANCE/AIRAC-%s/html/eAIP/FR-%s-fr-FR.html" % [
|
59
|
-
options[:airac].date.strftime('%d_%^b_%Y'), # 04_JAN_2018
|
60
|
-
options[:airac].date.xmlschema, # 2018-01-04
|
61
|
-
aip_file # ENR-5.1 or AD-2.LFMV
|
62
|
-
]
|
63
|
-
end
|
64
|
-
|
65
|
-
# Templates
|
66
|
-
|
67
|
-
def organisation_lf
|
68
|
-
@organisation_lf ||= AIXM.organisation(
|
69
|
-
name: 'FRANCE',
|
70
|
-
type: 'S'
|
71
|
-
).tap do |organisation|
|
72
|
-
organisation.id = 'LF'
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# Transformations
|
77
|
-
|
78
|
-
def cleanup(node:)
|
79
|
-
node.tap do |root|
|
80
|
-
root.css('del').each { |n| n.remove } # remove deleted entries
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def anglicise(name:)
|
85
|
-
name.uptrans.tap do |string|
|
86
|
-
ANGLICISE_MAP.each do |regexp, replacement|
|
87
|
-
string.gsub!(regexp, replacement)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
# Parsers
|
93
|
-
|
94
|
-
def source_for(element)
|
95
|
-
[
|
96
|
-
options[:region],
|
97
|
-
@aip.split('-').first,
|
98
|
-
@aip,
|
99
|
-
options[:airac].date.xmlschema,
|
100
|
-
element.line
|
101
|
-
].join('|')
|
102
|
-
end
|
103
|
-
|
104
|
-
def xy_from(td)
|
105
|
-
parts = td.text.strip.split(/\s+/)
|
106
|
-
AIXM.xy(lat: parts[0], long: parts[1])
|
107
|
-
end
|
108
|
-
|
109
|
-
def z_from(limit)
|
110
|
-
case limit
|
111
|
-
when nil then nil
|
112
|
-
when 'SFC' then AIXM::GROUND
|
113
|
-
when 'UNL' then AIXM::UNLIMITED
|
114
|
-
when /(\d+)ftASFC/ then AIXM.z($1.to_i, :qfe)
|
115
|
-
when /(\d+)ftAMSL/ then AIXM.z($1.to_i, :qnh)
|
116
|
-
when /FL(\d+)/ then AIXM.z($1.to_i, :qne)
|
117
|
-
else fail "z `#{limit}' not recognized"
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def layer_from(td)
|
122
|
-
above, below = td.text.gsub(/ /, '').split(/\n+/).select(&:blank_to_nil).split { |e| e.match? '---+' }
|
123
|
-
above.reverse!
|
124
|
-
AIXM.layer(
|
125
|
-
vertical_limits: AIXM.vertical_limits(
|
126
|
-
max_z: z_from(above[1]),
|
127
|
-
upper_z: z_from(above[0]),
|
128
|
-
lower_z: z_from(below[0]),
|
129
|
-
min_z: z_from(below[1])
|
130
|
-
)
|
131
|
-
)
|
132
|
-
end
|
133
|
-
|
134
|
-
def geometry_from(td)
|
135
|
-
AIXM.geometry.tap do |geometry|
|
136
|
-
buffer = {}
|
137
|
-
td.text.gsub(/\s+/, ' ').strip.split(/ - /).append('end').each do |element|
|
138
|
-
case element
|
139
|
-
when /arc (anti-)?horaire .+ sur (\S+) , (\S+)/i
|
140
|
-
geometry << AIXM.arc(
|
141
|
-
xy: buffer.delete(:xy),
|
142
|
-
center_xy: AIXM.xy(lat: $2, long: $3),
|
143
|
-
clockwise: $1.nil?
|
144
|
-
)
|
145
|
-
when /cercle de ([\d\.]+) (NM|km|m) .+ sur (\S+) , (\S+)/i
|
146
|
-
geometry << AIXM.circle(
|
147
|
-
center_xy: AIXM.xy(lat: $3, long: $4),
|
148
|
-
radius: AIXM.d($1.to_f, $2)
|
149
|
-
)
|
150
|
-
when /end|(\S+) , (\S+)/
|
151
|
-
geometry << AIXM.point(xy: buffer[:xy]) if buffer.has_key?(:xy)
|
152
|
-
buffer[:xy] = AIXM.xy(lat: $1, long: $2) if $1
|
153
|
-
when /^frontière ([\w-]+)/i, /^(\D[^(]+)/i
|
154
|
-
border_name = BORDERS.fetch($1.downcase.strip)
|
155
|
-
buffer[:xy] ||= INTERSECTIONS.fetch("#{buffer[:border_name]}|#{border_name}")
|
156
|
-
buffer[:border_name] = border_name
|
157
|
-
if border_name == 'FRANCE_SPAIN' # specify which part of this split border
|
158
|
-
border_name += buffer[:xy].lat < 42.55 ? '_EAST' : '_WEST'
|
159
|
-
end
|
160
|
-
geometry << AIXM.border(
|
161
|
-
xy: buffer.delete(:xy),
|
162
|
-
name: border_name
|
163
|
-
)
|
164
|
-
else
|
165
|
-
fail "geometry `#{element}' not recognized"
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
def timetable_from(td)
|
172
|
-
AIXM::H24 if td.text.gsub(/\W/, '') == 'H24'
|
173
|
-
end
|
174
|
-
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
@@ -1,123 +0,0 @@
|
|
1
|
-
require_relative '../../spec_helper'
|
2
|
-
|
3
|
-
using AIPP::Refinements
|
4
|
-
|
5
|
-
describe AIPP::Refinements do
|
6
|
-
|
7
|
-
context String do
|
8
|
-
describe :blank_to_nil do
|
9
|
-
it "must convert blank to nil" do
|
10
|
-
"\n \n ".blank_to_nil.must_be :nil?
|
11
|
-
end
|
12
|
-
|
13
|
-
it "must leave non-blank untouched" do
|
14
|
-
"foobar".blank_to_nil.must_equal "foobar"
|
15
|
-
end
|
16
|
-
|
17
|
-
it "must leave non-blank with whitespace untouched" do
|
18
|
-
"\nfoo bar\n".blank_to_nil.must_equal "\nfoo bar\n"
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe :blank? do
|
23
|
-
it "all whitespace must return true" do
|
24
|
-
"\n \n ".blank?.must_equal true
|
25
|
-
end
|
26
|
-
|
27
|
-
it "not all whitespace must return false" do
|
28
|
-
"\nfoo bar\n".blank?.must_equal false
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
describe :classify do
|
33
|
-
it "must convert file name to class name" do
|
34
|
-
"ENR-5.1".classify.must_equal "ENR51"
|
35
|
-
"helper".classify.must_equal "Helper"
|
36
|
-
"foo_bar".classify.must_equal "FooBar"
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
context NilClass do
|
42
|
-
describe :blank_to_nil do
|
43
|
-
it "must return self" do
|
44
|
-
nil.blank_to_nil.must_be :nil?
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe :blank? do
|
49
|
-
it "must return true" do
|
50
|
-
nil.blank?.must_equal true
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
context Array do
|
56
|
-
describe :constantize do
|
57
|
-
it "must convert to constant" do
|
58
|
-
%w(AIPP Refinements).constantize.must_equal AIPP::Refinements
|
59
|
-
end
|
60
|
-
|
61
|
-
it "fails to convert to inexistant constant" do
|
62
|
-
-> { %w(Foo Bar).constantize }.must_raise NameError
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
context Enumerable do
|
68
|
-
describe :split do
|
69
|
-
context "by object" do
|
70
|
-
it "must split at matching element" do
|
71
|
-
[1, 2, 0, 3, 4].split(0).must_equal [[1, 2], [3, 4]]
|
72
|
-
end
|
73
|
-
|
74
|
-
it "won't split when no element matches" do
|
75
|
-
[1, 2, 3].split(0).must_equal [[1, 2, 3]]
|
76
|
-
end
|
77
|
-
|
78
|
-
it "won't split zero length enumerable" do
|
79
|
-
[].split(0).must_equal []
|
80
|
-
end
|
81
|
-
|
82
|
-
it "must keep leading empty subarrays" do
|
83
|
-
[0, 1, 2, 0, 3, 4].split(0).must_equal [[], [1, 2], [3, 4]]
|
84
|
-
end
|
85
|
-
|
86
|
-
it "must keep empty subarrays in the middle" do
|
87
|
-
[1, 2, 0, 0, 3, 4].split(0).must_equal [[1, 2], [], [3, 4]]
|
88
|
-
end
|
89
|
-
|
90
|
-
it "must drop trailing empty subarrays" do
|
91
|
-
[1, 2, 0, 3, 4, 0].split(0).must_equal [[1, 2], [3, 4]]
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
context "by block" do
|
96
|
-
it "must split at matching element" do
|
97
|
-
[1, 2, 0, 3, 4].split { |e| e.zero? }.must_equal [[1, 2], [3, 4]]
|
98
|
-
end
|
99
|
-
|
100
|
-
it "won't split when no element matches" do
|
101
|
-
[1, 2, 3].split { |e| e.zero? }.must_equal [[1, 2, 3]]
|
102
|
-
end
|
103
|
-
|
104
|
-
it "won't split zero length enumerable" do
|
105
|
-
[].split { |e| e.zero? }.must_equal []
|
106
|
-
end
|
107
|
-
|
108
|
-
it "must keep leading empty subarrays" do
|
109
|
-
[0, 1, 2, 0, 3, 4].split { |e| e.zero? }.must_equal [[], [1, 2], [3, 4]]
|
110
|
-
end
|
111
|
-
|
112
|
-
it "must keep empty subarrays in the middle" do
|
113
|
-
[1, 2, 0, 0, 3, 4].split { |e| e.zero? }.must_equal [[1, 2], [], [3, 4]]
|
114
|
-
end
|
115
|
-
|
116
|
-
it "must drop trailing empty subarrays" do
|
117
|
-
[1, 2, 0, 3, 4, 0].split { |e| e.zero? }.must_equal [[1, 2], [3, 4]]
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
end
|