aipp 0.2.1 → 0.2.2
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/.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
|