fat_core 0.0.1
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 +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +46 -0
- data/Rakefile +1 -0
- data/fat_core.gemspec +29 -0
- data/lib/fat_core.rb +19 -0
- data/lib/fat_core/array.rb +14 -0
- data/lib/fat_core/date.rb +757 -0
- data/lib/fat_core/enumerable.rb +7 -0
- data/lib/fat_core/hash.rb +33 -0
- data/lib/fat_core/kernel.rb +9 -0
- data/lib/fat_core/latex_eruby.rb +11 -0
- data/lib/fat_core/nil.rb +9 -0
- data/lib/fat_core/numeric.rb +87 -0
- data/lib/fat_core/period.rb +410 -0
- data/lib/fat_core/range.rb +192 -0
- data/lib/fat_core/string.rb +184 -0
- data/lib/fat_core/symbol.rb +17 -0
- data/lib/fat_core/version.rb +3 -0
- data/spec/lib/date_spec.rb +320 -0
- data/spec/lib/kernel_spec.rb +11 -0
- data/spec/lib/numeric_spec.rb +34 -0
- data/spec/lib/period_spec.rb +294 -0
- data/spec/lib/range_spec.rb +246 -0
- data/spec/lib/string_spec.rb +128 -0
- data/spec/spec_helper.rb +23 -0
- metadata +178 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.dirname(File.absolute_path(__FILE__)) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe Numeric do
|
4
|
+
it "should properly round up" do
|
5
|
+
236.5555.commas(2).should == '236.56'
|
6
|
+
-236.5555.commas(2).should == '-236.56'
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should properly round down" do
|
10
|
+
236.5512.commas(2).should == '236.55'
|
11
|
+
-236.5512.commas(2).should == '-236.55'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should place commas properly" do
|
15
|
+
123456789.0123.commas(2).should == '123,456,789.01'
|
16
|
+
-123456789.0123.commas(2).should == '-123,456,789.01'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should place commas properly with no fraction" do
|
20
|
+
123456789.commas.should == '123,456,789'
|
21
|
+
-123456789.commas.should == '-123,456,789'
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should not place commas in a number with exponent" do
|
25
|
+
123456.789e100.commas.should == '1.23456789e+105'
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should be able to convert itself into an H:M:S string" do
|
29
|
+
expect(60.secs_to_hms).to eq('00:01:00')
|
30
|
+
expect(120.secs_to_hms).to eq('00:02:00')
|
31
|
+
expect(6584.secs_to_hms).to eq('01:49:44')
|
32
|
+
expect(6584.35.secs_to_hms).to eq('01:49:44.35')
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,294 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Period do
|
4
|
+
before :each do
|
5
|
+
# Pretend it is this date. Not at beg or end of year, quarter,
|
6
|
+
# month, or week. It is a Wednesday
|
7
|
+
Date.stub(:today).and_return(Date.parse('2012-07-18'))
|
8
|
+
@test_today = Date.parse('2012-07-18')
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "initialization" do
|
12
|
+
|
13
|
+
it "should be initializable with date strings" do
|
14
|
+
Period.new('2013-01-01', '2013-12-13').should be_instance_of Period
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should be initializable with Dates" do
|
18
|
+
Period.new(Date.parse('2013-01-01'), Date.parse('2013-12-13')).
|
19
|
+
should be_instance_of Period
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should raise a ArgumentError if last > first" do
|
23
|
+
expect {
|
24
|
+
Period.new('2013-01-01', '2012-12-31')
|
25
|
+
}.to raise_error ArgumentError
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should raise a ArgumentError if initialized with invalid date string" do
|
29
|
+
expect {
|
30
|
+
Period.new('2013-01-01', '2013-12-32')
|
31
|
+
}.to raise_error ArgumentError
|
32
|
+
expect {
|
33
|
+
Period.new('2013-13-01', '2013-12-31')
|
34
|
+
}.to raise_error ArgumentError
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should raise a ArgumentError if initialized otherwise" do
|
38
|
+
expect {
|
39
|
+
Period.new(2013-01-01, 2013-12-31)
|
40
|
+
}.to raise_error ArgumentError
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "class methods" do
|
45
|
+
|
46
|
+
it "should know the days in a chunk sym" do
|
47
|
+
Period.chunk_sym_to_days(:year).should eq(365)
|
48
|
+
Period.chunk_sym_to_days(:quarter).should eq(90)
|
49
|
+
Period.chunk_sym_to_days(:bimonth).should eq(60)
|
50
|
+
Period.chunk_sym_to_days(:month).should eq(30)
|
51
|
+
Period.chunk_sym_to_days(:semimonth).should eq(15)
|
52
|
+
Period.chunk_sym_to_days(:biweek).should eq(14)
|
53
|
+
Period.chunk_sym_to_days(:week).should eq(7)
|
54
|
+
Period.chunk_sym_to_days(:day).should eq(1)
|
55
|
+
Period.chunk_sym_to_days(:irregular).should eq(30)
|
56
|
+
expect {
|
57
|
+
Period.chunk_sym_to_days(:eon)
|
58
|
+
}.to raise_error ArgumentError
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should know the chunk sym for given days but only :year, :quarter, :month" do
|
62
|
+
(356..376).each { |d| Period.days_to_chunk_sym(d).should eq(:year) }
|
63
|
+
(86..96).each { |d| Period.days_to_chunk_sym(d).should eq(:quarter) }
|
64
|
+
(28..31).each { |d| Period.days_to_chunk_sym(d).should eq(:month) }
|
65
|
+
Period.days_to_chunk_sym(7).should eq(:week)
|
66
|
+
Period.days_to_chunk_sym(1).should eq(:day)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should know what to call a chunk based on its size" do
|
70
|
+
expect(Period.new('2011-01-01', '2011-12-31').chunk_name).to eq('Year')
|
71
|
+
expect(Period.new('2011-01-01', '2011-03-31').chunk_name).to eq('Quarter')
|
72
|
+
expect(Period.new('2011-01-01', '2011-01-31').chunk_name).to eq('Month')
|
73
|
+
expect(Period.new('2011-01-01', '2011-01-07').chunk_name).to eq('Week')
|
74
|
+
expect(Period.new('2011-01-01', '2011-01-01').chunk_name).to eq('Day')
|
75
|
+
expect(Period.new('2011-01-01', '2011-01-21').chunk_name).to eq('Period')
|
76
|
+
# Only size matters, not whether the period begins and ends on
|
77
|
+
# calendar unit boundaries.
|
78
|
+
expect(Period.new('2011-02-11', '2011-03-10').chunk_name).to eq('Month')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "instance methods" do
|
83
|
+
|
84
|
+
it "should be able to compare for equality" do
|
85
|
+
pp1 = Period.new('2013-01-01', '2013-12-31')
|
86
|
+
pp2 = Period.new('2013-01-01', '2013-12-31')
|
87
|
+
pp3 = Period.new('2013-01-01', '2013-12-30')
|
88
|
+
(pp1 == pp2).should be_true
|
89
|
+
(pp1 == pp3).should_not be_true
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should be able to convert into a Range" do
|
93
|
+
pp = Period.new('2013-01-01', '2013-12-31')
|
94
|
+
rr = Period.new('2013-01-01', '2013-12-31').to_range
|
95
|
+
rr.should be_instance_of Range
|
96
|
+
rr.first.should eq(pp.first)
|
97
|
+
rr.first.should eq(pp.first)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should be able to tell if it contains a date" do
|
101
|
+
pp = Period.new('2013-01-01', '2013-12-31')
|
102
|
+
pp.contains?(Date.parse('2013-01-01')).should be_true
|
103
|
+
pp.contains?(Date.parse('2013-07-04')).should be_true
|
104
|
+
pp.contains?(Date.parse('2013-12-31')).should be_true
|
105
|
+
pp.contains?(Date.parse('2012-07-04')).should be_false
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should be able to make a concise period string" do
|
109
|
+
Period.new('2013-01-01', '2013-12-31').to_s.
|
110
|
+
should eq('2013')
|
111
|
+
Period.new('2013-04-01', '2013-06-30').to_s.
|
112
|
+
should eq('2013-2Q')
|
113
|
+
Period.new('2013-03-01', '2013-03-31').to_s.
|
114
|
+
should eq('2013-03')
|
115
|
+
Period.new('2013-03-11', '2013-10-31').to_s.
|
116
|
+
should eq('2013-03-11 to 2013-10-31')
|
117
|
+
end
|
118
|
+
|
119
|
+
# Note in the following that first period must begin within self.
|
120
|
+
it "should be able to chunk into years" do
|
121
|
+
chunks = Period.new('2009-12-15', '2013-01-10').chunks(size: :year)
|
122
|
+
chunks.size.should eq(3)
|
123
|
+
chunks[0].first.iso.should eq('2010-01-01')
|
124
|
+
chunks[0].last.iso.should eq('2010-12-31')
|
125
|
+
chunks[1].first.iso.should eq('2011-01-01')
|
126
|
+
chunks[1].last.iso.should eq('2011-12-31')
|
127
|
+
chunks[2].first.iso.should eq('2012-01-01')
|
128
|
+
chunks[2].last.iso.should eq('2012-12-31')
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should be able to chunk into quarters" do
|
132
|
+
chunks = Period.new('2009-12-15', '2013-01-10').chunks(size: :quarter)
|
133
|
+
chunks.size.should eq(12)
|
134
|
+
chunks[0].first.iso.should eq('2010-01-01')
|
135
|
+
chunks[0].last.iso.should eq('2010-03-31')
|
136
|
+
chunks[1].first.iso.should eq('2010-04-01')
|
137
|
+
chunks[1].last.iso.should eq('2010-06-30')
|
138
|
+
chunks[2].first.iso.should eq('2010-07-01')
|
139
|
+
chunks[2].last.iso.should eq('2010-09-30')
|
140
|
+
chunks.last.first.iso.should eq('2012-10-01')
|
141
|
+
chunks.last.last.iso.should eq('2012-12-31')
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should be able to chunk into bimonths" do
|
145
|
+
chunks = Period.new('2009-12-15', '2013-01-10').chunks(size: :bimonth)
|
146
|
+
chunks.size.should eq(18)
|
147
|
+
chunks[0].first.iso.should eq('2010-01-01')
|
148
|
+
chunks[0].last.iso.should eq('2010-02-28')
|
149
|
+
chunks[1].first.iso.should eq('2010-03-01')
|
150
|
+
chunks[1].last.iso.should eq('2010-04-30')
|
151
|
+
chunks[2].first.iso.should eq('2010-05-01')
|
152
|
+
chunks[2].last.iso.should eq('2010-06-30')
|
153
|
+
chunks.last.first.iso.should eq('2012-11-01')
|
154
|
+
chunks.last.last.iso.should eq('2012-12-31')
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should be able to chunk into months" do
|
158
|
+
chunks = Period.new('2009-12-15', '2013-01-10').chunks(size: :month)
|
159
|
+
chunks.size.should eq(36)
|
160
|
+
chunks[0].first.iso.should eq('2010-01-01')
|
161
|
+
chunks[0].last.iso.should eq('2010-01-31')
|
162
|
+
chunks[1].first.iso.should eq('2010-02-01')
|
163
|
+
chunks[1].last.iso.should eq('2010-02-28')
|
164
|
+
chunks[2].first.iso.should eq('2010-03-01')
|
165
|
+
chunks[2].last.iso.should eq('2010-03-31')
|
166
|
+
chunks.last.first.iso.should eq('2012-12-01')
|
167
|
+
chunks.last.last.iso.should eq('2012-12-31')
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should be able to chunk into semimonths" do
|
171
|
+
chunks = Period.new('2009-12-25', '2013-01-10').chunks(size: :semimonth)
|
172
|
+
chunks.size.should eq(72)
|
173
|
+
chunks[0].first.iso.should eq('2010-01-01')
|
174
|
+
chunks[0].last.iso.should eq('2010-01-15')
|
175
|
+
chunks[1].first.iso.should eq('2010-01-16')
|
176
|
+
chunks[1].last.iso.should eq('2010-01-31')
|
177
|
+
chunks[2].first.iso.should eq('2010-02-01')
|
178
|
+
chunks[2].last.iso.should eq('2010-02-15')
|
179
|
+
chunks.last.first.iso.should eq('2012-12-16')
|
180
|
+
chunks.last.last.iso.should eq('2012-12-31')
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should be able to chunk into biweeks" do
|
184
|
+
chunks = Period.new('2009-12-29', '2013-01-10').chunks(size: :biweek)
|
185
|
+
expect(chunks.size).to be >=(26*3)
|
186
|
+
chunks[0].first.iso.should eq('2010-01-04')
|
187
|
+
chunks[0].last.iso.should eq('2010-01-17')
|
188
|
+
chunks[1].first.iso.should eq('2010-01-18')
|
189
|
+
chunks[1].last.iso.should eq('2010-01-31')
|
190
|
+
chunks[2].first.iso.should eq('2010-02-01')
|
191
|
+
chunks[2].last.iso.should eq('2010-02-14')
|
192
|
+
chunks.last.first.iso.should eq('2012-12-17')
|
193
|
+
chunks.last.last.iso.should eq('2012-12-30')
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should be able to chunk into weeks" do
|
197
|
+
chunks = Period.new('2010-01-01', '2012-12-31').chunks(size: :week)
|
198
|
+
expect(chunks.size).to be >=(52*3)
|
199
|
+
chunks[0].first.iso.should eq('2010-01-04')
|
200
|
+
chunks[0].last.iso.should eq('2010-01-10')
|
201
|
+
chunks[1].first.iso.should eq('2010-01-11')
|
202
|
+
chunks[1].last.iso.should eq('2010-01-17')
|
203
|
+
chunks[2].first.iso.should eq('2010-01-18')
|
204
|
+
chunks[2].last.iso.should eq('2010-01-24')
|
205
|
+
chunks.last.first.iso.should eq('2012-12-24')
|
206
|
+
chunks.last.last.iso.should eq('2012-12-30')
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should be able to chunk into days" do
|
210
|
+
chunks = Period.new('2012-12-28', '2012-12-31').chunks(size: :day)
|
211
|
+
chunks.size.should eq(4)
|
212
|
+
chunks[0].first.iso.should eq('2012-12-28')
|
213
|
+
chunks[0].last.iso.should eq('2012-12-28')
|
214
|
+
chunks[1].first.iso.should eq('2012-12-29')
|
215
|
+
chunks[1].last.iso.should eq('2012-12-29')
|
216
|
+
chunks[2].first.iso.should eq('2012-12-30')
|
217
|
+
chunks[2].last.iso.should eq('2012-12-30')
|
218
|
+
chunks.last.first.iso.should eq('2012-12-31')
|
219
|
+
chunks.last.last.iso.should eq('2012-12-31')
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should not include a partial final chunk by default" do
|
223
|
+
chunks = Period.new('2012-01-01', '2012-03-30').chunks(size: :month)
|
224
|
+
chunks.size.should eq(2)
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should include a partial final chunk if partial_last" do
|
228
|
+
chunks = Period.new('2012-01-01', '2012-03-30').
|
229
|
+
chunks(size: :month, partial_last: true)
|
230
|
+
chunks.size.should eq(3)
|
231
|
+
chunks.last.first.should eq(Date.parse('2012-03-01'))
|
232
|
+
chunks.last.last.should eq(Date.parse('2012-03-30'))
|
233
|
+
end
|
234
|
+
|
235
|
+
it "should include a final chunk beyond end_date if round_up" do
|
236
|
+
chunks = Period.new('2012-01-01', '2012-03-30').
|
237
|
+
chunks(size: :month, round_up_last: true)
|
238
|
+
chunks.size.should eq(3)
|
239
|
+
chunks.last.first.should eq(Date.parse('2012-03-01'))
|
240
|
+
chunks.last.last.should eq(Date.parse('2012-03-31'))
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should not include a partial initial chunk by default" do
|
244
|
+
chunks = Period.new('2012-01-13', '2012-03-31').chunks(size: :month)
|
245
|
+
chunks.size.should eq(2)
|
246
|
+
chunks[0].first.should eq(Date.parse('2012-02-01'))
|
247
|
+
chunks[0].last.should eq(Date.parse('2012-02-29'))
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should include a partial initial chunk by if partial_first" do
|
251
|
+
chunks = Period.new('2012-01-13', '2012-03-31').
|
252
|
+
chunks(size: :month, partial_first: true)
|
253
|
+
chunks.size.should eq(3)
|
254
|
+
chunks[0].first.should eq(Date.parse('2012-01-13'))
|
255
|
+
chunks[0].last.should eq(Date.parse('2012-01-31'))
|
256
|
+
end
|
257
|
+
|
258
|
+
it "should include a final chunk beyond end_date if round_up" do
|
259
|
+
chunks = Period.new('2012-01-01', '2012-03-30').
|
260
|
+
chunks(size: :month, round_up_last: true)
|
261
|
+
chunks.size.should eq(3)
|
262
|
+
chunks.last.first.should eq(Date.parse('2012-03-01'))
|
263
|
+
chunks.last.last.should eq(Date.parse('2012-03-31'))
|
264
|
+
end
|
265
|
+
|
266
|
+
it "should be able to its chunk_sym" do
|
267
|
+
Period.new('2013-01-01', '2013-12-31').chunk_sym.should eq(:year)
|
268
|
+
Period.new('2012-01-01', '2013-12-31').chunk_sym.should_not eq(:year)
|
269
|
+
|
270
|
+
Period.new('2013-04-01', '2013-06-30').chunk_sym.should eq(:quarter)
|
271
|
+
Period.new('2013-04-01', '2013-09-30').chunk_sym.should_not eq(:quarter)
|
272
|
+
|
273
|
+
Period.new('2013-03-01', '2013-04-30').chunk_sym.should eq(:bimonth)
|
274
|
+
Period.new('2013-03-01', '2013-06-30').chunk_sym.should_not eq(:bimonth)
|
275
|
+
|
276
|
+
Period.new('2013-04-01', '2013-04-30').chunk_sym.should eq(:month)
|
277
|
+
Period.new('2013-04-01', '2013-05-30').chunk_sym.should_not eq(:month)
|
278
|
+
|
279
|
+
Period.new('2013-05-16', '2013-05-31').chunk_sym.should eq(:semimonth)
|
280
|
+
Period.new('2013-05-16', '2013-06-30').chunk_sym.should_not eq(:semimonth)
|
281
|
+
|
282
|
+
Period.new('2013-11-04', '2013-11-17').chunk_sym.should eq(:biweek)
|
283
|
+
Period.new('2013-11-04', '2013-11-24').chunk_sym.should_not eq(:biweek)
|
284
|
+
|
285
|
+
Period.new('2013-11-11', '2013-11-17').chunk_sym.should eq(:week)
|
286
|
+
Period.new('2013-11-11', '2013-11-24').chunk_sym.should_not eq(:week)
|
287
|
+
|
288
|
+
Period.new('2013-11-10', '2013-11-10').chunk_sym.should eq(:day)
|
289
|
+
Period.new('2013-11-10', '2013-11-11').chunk_sym.should_not eq(:day)
|
290
|
+
|
291
|
+
Period.new('2013-11-02', '2013-12-16').chunk_sym.should eq(:irregular)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
@@ -0,0 +1,246 @@
|
|
1
|
+
require File.dirname(File.absolute_path(__FILE__)) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe Range do
|
4
|
+
describe "set operations" do
|
5
|
+
it "should know if it is a subset of another range" do
|
6
|
+
expect((4..8)).to be_subset_of((2..9))
|
7
|
+
expect((4..8)).to be_subset_of((4..8))
|
8
|
+
expect((4..8)).not_to be_subset_of((2..7))
|
9
|
+
expect((4..8)).not_to be_subset_of((5..8))
|
10
|
+
expect((4..8)).not_to be_subset_of((11..20))
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should know if it is a proper subset of another range" do
|
14
|
+
expect((4..8)).to be_proper_subset_of((2..9))
|
15
|
+
expect((4..8)).not_to be_proper_subset_of((4..8))
|
16
|
+
expect((4..8)).not_to be_proper_subset_of((2..7))
|
17
|
+
expect((4..8)).not_to be_proper_subset_of((5..8))
|
18
|
+
expect((4..8)).not_to be_proper_subset_of((11..20))
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should know if it is a superset of another range" do
|
22
|
+
expect((4..8)).to be_superset_of((5..7))
|
23
|
+
expect((4..8)).to be_superset_of((6..8))
|
24
|
+
expect((4..8)).to be_superset_of((4..7))
|
25
|
+
expect((4..8)).to be_superset_of((4..8))
|
26
|
+
expect((4..8)).not_to be_superset_of((2..9))
|
27
|
+
expect((4..8)).not_to be_superset_of((2..8))
|
28
|
+
expect((4..8)).not_to be_superset_of((4..9))
|
29
|
+
expect((4..8)).not_to be_superset_of((8..20))
|
30
|
+
expect((4..8)).not_to be_superset_of((0..4))
|
31
|
+
expect((4..8)).not_to be_superset_of((0..3))
|
32
|
+
expect((4..8)).not_to be_superset_of((9..20))
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should know if it is a superset of another range" do
|
36
|
+
expect((4..8)).to be_proper_superset_of((5..7))
|
37
|
+
expect((4..8)).not_to be_proper_superset_of((6..8))
|
38
|
+
expect((4..8)).not_to be_proper_superset_of((4..7))
|
39
|
+
expect((4..8)).not_to be_proper_superset_of((4..8))
|
40
|
+
expect((4..8)).not_to be_proper_superset_of((2..9))
|
41
|
+
expect((4..8)).not_to be_proper_superset_of((2..8))
|
42
|
+
expect((4..8)).not_to be_proper_superset_of((4..9))
|
43
|
+
expect((4..8)).not_to be_proper_superset_of((8..20))
|
44
|
+
expect((4..8)).not_to be_proper_superset_of((0..4))
|
45
|
+
expect((4..8)).not_to be_proper_superset_of((0..3))
|
46
|
+
expect((4..8)).not_to be_proper_superset_of((9..20))
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should know its intersection with another range" do
|
50
|
+
((0..10) & (5..20)).should eq((5..10))
|
51
|
+
((0..10) & (5..20)).should eq((5..20) & (0..10))
|
52
|
+
((0..10) & (10..20)).should eq((10..10))
|
53
|
+
end
|
54
|
+
|
55
|
+
it "intersection should return nil if there is no overlap" do
|
56
|
+
((0..10) & (15..20)).should be_nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should know its union with another range" do
|
60
|
+
((0..10) + (5..20)).should eq((0..20))
|
61
|
+
((0..10) + (5..20)).should eq((5..20) + (0..10))
|
62
|
+
((0..10) + (10..20)).should eq((0..20))
|
63
|
+
end
|
64
|
+
|
65
|
+
it "union should return nil if there is no overlap" do
|
66
|
+
((0..10) & (15..20)).should be_nil
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should know the difference with another range" do
|
70
|
+
# Other is same as self
|
71
|
+
expect(((4..10) - (4..10)).size).to eq(0)
|
72
|
+
expect(((4..10) - (4..10))).to be_empty
|
73
|
+
|
74
|
+
# Other is proper subset of self
|
75
|
+
expect(((4..10) - (6..7)).first).to eq((4..5))
|
76
|
+
expect(((4..10) - (6..7)).last).to eq((8..10))
|
77
|
+
expect(((4..10) - (6..10)).first).to eq((4..5))
|
78
|
+
expect(((4..10) - (4..7)).last).to eq((8..10))
|
79
|
+
|
80
|
+
# Other overlaps on the left
|
81
|
+
expect(((4..10) - (0..6)).size).to eq(1)
|
82
|
+
expect(((4..10) - (0..6)).first).to eq((7..10))
|
83
|
+
|
84
|
+
expect(((4..10) - (4..6)).size).to eq(1)
|
85
|
+
expect(((4..10) - (4..6)).first).to eq((7..10))
|
86
|
+
|
87
|
+
# Other overlaps on the right
|
88
|
+
expect(((4..10) - (7..11)).size).to eq(1)
|
89
|
+
expect(((4..10) - (7..11)).first).to eq((4..6))
|
90
|
+
|
91
|
+
expect(((4..10) - (7..10)).size).to eq(1)
|
92
|
+
expect(((4..10) - (7..10)).last).to eq((4..6))
|
93
|
+
|
94
|
+
# Other does not overlap
|
95
|
+
expect((4..10) - (13..20)).to be_empty
|
96
|
+
expect((4..10) - (1..3)).to be_empty
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "joining" do
|
101
|
+
it "should be able to join contiguous ranges" do
|
102
|
+
(0..3).join(4..8).should == (0..8)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should return nil on join of non-contiguous ranges" do
|
106
|
+
(0..3).join(5..8).should be_nil
|
107
|
+
(0...3).join(4..8).should be_nil
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should work with Floats, allowing single-point overlap" do
|
111
|
+
(0.0..3.0).join(3.0..8.2).should == (0.0..8.2)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "spanning" do
|
116
|
+
it "should be able to determine whether it is spanned by a set of ranges" do
|
117
|
+
(0..10).should be_spanned_by([(0..3), (4..6), (7..10)])
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should be determine that overlapping ranges do not span" do
|
121
|
+
(0..10).should_not be_spanned_by([(0..3), (3..6), (7..10)])
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should allow spanning ranges to be any Enumerable" do
|
125
|
+
require 'set'
|
126
|
+
set = [(0..3), (4..6), (7..10)].to_set
|
127
|
+
(0..10).should be_spanned_by(set)
|
128
|
+
set = [(0...3), (4..6), (7..10)].to_set
|
129
|
+
(0..10).should_not be_spanned_by(set)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should allow the spanning set to be wider than itself" do
|
133
|
+
set = [(0..3), (4..6), (7..10)].to_set
|
134
|
+
(2..8).should be_spanned_by(set)
|
135
|
+
(5..6).should be_spanned_by(set)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "overlapping a single range" do
|
140
|
+
it "should know if another range overlaps it" do
|
141
|
+
(0..10).overlaps?(-3..5).should be_true
|
142
|
+
(0..10).overlaps?(3..5).should be_true
|
143
|
+
(0..10).overlaps?(8..15).should be_true
|
144
|
+
(0..10).overlaps?(0..10).should be_true
|
145
|
+
(0..10).overlaps?(11..12).should be_false
|
146
|
+
(0..10).overlaps?(-11..-1).should be_false
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should be able to determine whether a set contains covered overlaps" do
|
150
|
+
(0..10).should have_overlaps_within([(0..3), (2..6), (7..10)])
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should not care about overlaps outside range" do
|
154
|
+
(11..15).should_not have_overlaps_within([(0..3), (2..6), (7..10)])
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should not count contiguous ranges as overlapping" do
|
158
|
+
(0..10).should_not have_overlaps_within([(0..3), (4..6), (7..10)])
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should not count non-contiguous ranges as overlapping" do
|
162
|
+
(0..10).should_not have_overlaps_within([(0..3), (4..6), (8..10)])
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should not count an empty set as overlapping" do
|
166
|
+
(0..10).should_not have_overlaps_within([])
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "coverage gaps" do
|
171
|
+
it "should return an empty array if ranges completely cover" do
|
172
|
+
(0..10).gaps([(-1..3), (4..8), (9..11)]).should be_empty
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should return array for itself if ranges are empty" do
|
176
|
+
(0..10).gaps([]).should eq([(0..10)])
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should return an array of gaps" do
|
180
|
+
gaps = (0..10).gaps([(0..3), (5..6), (9..10)])
|
181
|
+
gaps[0].should eq((4..4))
|
182
|
+
gaps[1].should eq((7..8))
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should allow ranges to extend before and after self" do
|
186
|
+
gaps = (0..10).gaps([(-3..3), (4..6), (7..13)])
|
187
|
+
gaps.should be_empty
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should return an gaps at beginning and end" do
|
191
|
+
gaps = (0..10).gaps([(2..3), (4..6), (7..8)])
|
192
|
+
gaps[0].should eq((0..1))
|
193
|
+
gaps[1].should eq((9..10))
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should work even if ranges are out of order" do
|
197
|
+
gaps = (0..10).gaps([(2..3), (7..8), (4..6)])
|
198
|
+
gaps[0].should eq((0..1))
|
199
|
+
gaps[1].should eq((9..10))
|
200
|
+
end
|
201
|
+
|
202
|
+
it "should work even if ranges overlap" do
|
203
|
+
gaps = (0..10).gaps([(-2..3), (2..8), (4..10)])
|
204
|
+
gaps.should be_empty
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
describe "coverage overlaps" do
|
209
|
+
it "should return an empty array if ranges are empty" do
|
210
|
+
(0..10).overlaps([]).should be_empty
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should return an empty array if ranges is same as self" do
|
214
|
+
(0..10).overlaps([(0..10)]).should be_empty
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should return an empty array if ranges is wider than self" do
|
218
|
+
(0..10).overlaps([(-5..15)]).should be_empty
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should return an empty array if ranges is narrower than self" do
|
222
|
+
(0..10).overlaps([(5..8)]).should be_empty
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should return an array of overlaps" do
|
226
|
+
overlaps = (0..10).overlaps([(0..3), (2..6), (4..10)])
|
227
|
+
overlaps.size.should eq(2)
|
228
|
+
overlaps[0].should eq((2..3))
|
229
|
+
overlaps[1].should eq((4..6))
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should not return any overlaps before self" do
|
233
|
+
overlaps = (0..10).overlaps([(-5..-3), (-4..-1), (0..3), (2..6), (4..10)])
|
234
|
+
overlaps.size.should eq(2)
|
235
|
+
overlaps[0].should eq((2..3))
|
236
|
+
overlaps[1].should eq((4..6))
|
237
|
+
end
|
238
|
+
|
239
|
+
it "should not return any overlaps after self" do
|
240
|
+
overlaps = (0..10).overlaps([(0..3), (2..6), (4..15), (11..20)])
|
241
|
+
overlaps.size.should eq(2)
|
242
|
+
overlaps[0].should eq((2..3))
|
243
|
+
overlaps[1].should eq((4..6))
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|