timeframe 0.2.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +11 -0
- data/Gemfile +0 -6
- data/Rakefile +3 -12
- data/lib/timeframe.rb +23 -7
- data/lib/timeframe/version.rb +1 -1
- data/spec/spec_helper.rb +4 -0
- data/spec/timeframe_spec.rb +332 -0
- data/timeframe.gemspec +4 -1
- metadata +48 -30
- data/lib/timeframe/core_ext/array.rb +0 -9
- data/test/helper.rb +0 -11
- data/test/test_timeframe.rb +0 -354
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f5c448bfd96b67234ea8986d23f6c9f668ffacb9
|
4
|
+
data.tar.gz: 0b348d4217d82035a8247f6a23546ce223af3e3f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c9fca9bff28ef6ea8cf6de692f79509a7200fe85efedc9c871f538c4e72402a329fc4e69d6737aa45064744b1bad35933c401920b3094a2de865c6d820fc4445
|
7
|
+
data.tar.gz: e65458296129a65a665f0cfd4357cd9fa34ee023613d4414887f951cc1199153542bf77c2d0c0ba1aa97c0c98006b19026efc71f3891a00d8450f4b86bdc4120
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
1.0.0 / 2017-06-22
|
2
|
+
|
3
|
+
* Breaking changes
|
4
|
+
|
5
|
+
* No more Array#multiple_timeframes_gaps_left_by (who knows what that was for)
|
6
|
+
|
7
|
+
* Enhancements
|
8
|
+
|
9
|
+
* Only uses active_support/core_ext/date
|
10
|
+
* Convert to rspec, modernize
|
11
|
+
|
1
12
|
0.2.1 / 2012-04-24
|
2
13
|
|
3
14
|
* Bug fixes
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -1,15 +1,6 @@
|
|
1
|
-
#!/usr/bin/env rake
|
2
1
|
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
3
|
|
4
|
-
|
5
|
-
require 'rake/testtask'
|
6
|
-
Rake::TestTask.new(:test) do |test|
|
7
|
-
test.libs << 'lib' << 'test'
|
8
|
-
test.pattern = 'test/**/test_*.rb'
|
9
|
-
test.verbose = true
|
10
|
-
end
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
11
5
|
|
12
|
-
task :default => :
|
13
|
-
|
14
|
-
require 'yard'
|
15
|
-
YARD::Rake::YardocTask.new
|
6
|
+
task :default => :spec
|
data/lib/timeframe.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'date'
|
2
2
|
require 'multi_json'
|
3
|
-
require 'active_support
|
4
|
-
require 'active_support/core_ext'
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_support/core_ext/date'
|
5
5
|
|
6
6
|
require 'timeframe/iso_8601'
|
7
7
|
|
@@ -94,10 +94,23 @@ class Timeframe
|
|
94
94
|
new *args
|
95
95
|
end
|
96
96
|
|
97
|
+
def to_date(v)
|
98
|
+
case v
|
99
|
+
when NilClass
|
100
|
+
nil
|
101
|
+
when Date
|
102
|
+
v
|
103
|
+
when Time
|
104
|
+
v.to_date
|
105
|
+
else
|
106
|
+
Date.parse v
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
97
110
|
private
|
98
111
|
|
99
112
|
def make_dates(start_date, end_date)
|
100
|
-
[start_date
|
113
|
+
[to_date(start_date), to_date(end_date)]
|
101
114
|
end
|
102
115
|
end
|
103
116
|
|
@@ -131,8 +144,8 @@ class Timeframe
|
|
131
144
|
end_date = Date.new(year+1, 1, 1)
|
132
145
|
end
|
133
146
|
|
134
|
-
start_date
|
135
|
-
end_date
|
147
|
+
start_date ||= Timeframe.to_date(args[0])
|
148
|
+
end_date ||= Timeframe.to_date(args[1])
|
136
149
|
|
137
150
|
raise ArgumentError, "Please supply a start and end date, `#{args.map(&:inspect).to_sentence}' is not enough" if start_date.nil? or end_date.nil?
|
138
151
|
raise ArgumentError, "Start date #{start_date} should be earlier than end date #{end_date}" if start_date > end_date
|
@@ -160,7 +173,7 @@ class Timeframe
|
|
160
173
|
when Date
|
161
174
|
(start_date...end_date).include?(obj)
|
162
175
|
when Time
|
163
|
-
# (start_date...end_date).include?(obj
|
176
|
+
# (start_date...end_date).include?(Date.parse(obj))
|
164
177
|
raise "this wasn't previously supported, but it could be"
|
165
178
|
when Timeframe
|
166
179
|
start_date <= obj.start_date and end_date >= obj.end_date
|
@@ -275,7 +288,10 @@ class Timeframe
|
|
275
288
|
|
276
289
|
# Returns the same Timeframe, only a year earlier
|
277
290
|
def last_year
|
278
|
-
self.class.new(
|
291
|
+
self.class.new(
|
292
|
+
Date.new(start_date.year - 1, start_date.month, start_date.day),
|
293
|
+
Date.new(end_date.year - 1, end_date.month, end_date.day)
|
294
|
+
)
|
279
295
|
end
|
280
296
|
|
281
297
|
def as_json(*)
|
data/lib/timeframe/version.rb
CHANGED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,332 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe Timeframe do
|
4
|
+
describe 'initialization' do
|
5
|
+
it 'should create a timeframe using date strings' do
|
6
|
+
tf = Timeframe.new('2008-02-14', '2008-05-10')
|
7
|
+
expect(tf.from).to eq(Date.parse('2008-02-14'))
|
8
|
+
expect(tf.to).to eq(Date.parse('2008-05-10'))
|
9
|
+
end
|
10
|
+
it 'should create a timeframe using date objects' do
|
11
|
+
start = Date.parse('2008-02-14')
|
12
|
+
finish = Date.parse('2008-05-10')
|
13
|
+
tf = Timeframe.new(start, finish)
|
14
|
+
expect(tf.from).to eq(start)
|
15
|
+
expect(tf.to).to eq(finish)
|
16
|
+
end
|
17
|
+
it "should accept months" do
|
18
|
+
timeframe = Timeframe.new(:month => 1)
|
19
|
+
expect(timeframe.from).to eq(Date.today.change(:month => 1, :day => 1))
|
20
|
+
expect(timeframe.to).to eq(Date.today.change(:month => 2, :day => 1))
|
21
|
+
end
|
22
|
+
it "should accept month names" do
|
23
|
+
timeframe = Timeframe.new(:month => 'february')
|
24
|
+
expect(timeframe.from).to eq(Date.today.change(:month => 2, :day => 1))
|
25
|
+
expect(timeframe.to).to eq(Date.today.change(:month => 3, :day => 1))
|
26
|
+
end
|
27
|
+
it "should accept years" do
|
28
|
+
timeframe = Timeframe.new(:year => 2004)
|
29
|
+
expect(timeframe.from).to eq(Date.new(2004, 1, 1))
|
30
|
+
expect(timeframe.to).to eq(Date.new(2005, 1, 1))
|
31
|
+
end
|
32
|
+
it "should accept years and months" do
|
33
|
+
timeframe = Timeframe.new(:year => 2005, :month => 5)
|
34
|
+
expect(timeframe.from).to eq(Date.new(2005, 5, 1))
|
35
|
+
expect(timeframe.to).to eq(Date.new(2005, 6, 1))
|
36
|
+
end
|
37
|
+
it "should not accept just one date argument" do
|
38
|
+
expect {
|
39
|
+
Timeframe.new Date.new(2007, 2, 1)
|
40
|
+
}.to raise_error(ArgumentError, /supply/)
|
41
|
+
end
|
42
|
+
it "should not accept end date that is earlier than start date" do
|
43
|
+
expect {
|
44
|
+
timeframe = Timeframe.new Date.new(2008, 1, 1), Date.new(2007, 1, 1)
|
45
|
+
}.to raise_error(ArgumentError, /earlier/)
|
46
|
+
end
|
47
|
+
it "should always accept timeframes that cross year boundaries" do
|
48
|
+
timeframe = Timeframe.new Date.new(2007, 1, 1), Date.new(2008, 1, 2)
|
49
|
+
expect(timeframe.start_date).to eq(Date.new(2007, 1, 1))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#inspect' do
|
54
|
+
it 'should return the time frame in readable text' do
|
55
|
+
start = Date.parse('2008-02-14')
|
56
|
+
finish = Date.parse('2008-05-10')
|
57
|
+
tf = Timeframe.new(start, finish)
|
58
|
+
expect(tf.inspect).to match(%r{<Timeframe\(-?\d+\) 86 days starting 2008-02-14 ending 2008-05-10>})
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe :constrained_new do
|
63
|
+
let(:start) { Date.parse('2008-02-14') }
|
64
|
+
let(:finish) { Date.parse('2008-05-10') }
|
65
|
+
let(:constraint_start) { Date.parse('2008-01-01') }
|
66
|
+
let(:constraint_finish) { Date.parse('2008-12-01') }
|
67
|
+
let(:constraint) { Timeframe.new(constraint_start, constraint_finish) }
|
68
|
+
|
69
|
+
it "should allow for constrained creation" do
|
70
|
+
constraint = Timeframe.new :year => 2008
|
71
|
+
may = Timeframe.new Date.new(2008,5,1), Date.new(2008,6,1)
|
72
|
+
january = Timeframe.new Date.new(2008,1,1), Date.new(2008,2,1)
|
73
|
+
expect(Timeframe.constrained_new(may.from, may.to, constraint)).to eq(may)
|
74
|
+
expect(Timeframe.constrained_new(Date.new(2007,1,1), Date.new(2010,1,1), constraint)).to eq(constraint)
|
75
|
+
expect(Timeframe.constrained_new(Date.new(2007,11,1), Date.new(2008,2,1), constraint)).to eq(january)
|
76
|
+
end
|
77
|
+
it 'should return a timeframe spanning start and end date if within constraint' do
|
78
|
+
tf = Timeframe.constrained_new(start, finish, constraint)
|
79
|
+
expect(tf.from).to eq(start)
|
80
|
+
expect(tf.to).to eq(finish)
|
81
|
+
end
|
82
|
+
it 'should return a timeframe spanning constraint start and end date if outside constraint' do
|
83
|
+
constraint = Timeframe.new(start, finish)
|
84
|
+
tf = Timeframe.constrained_new(constraint_start, constraint_finish, constraint)
|
85
|
+
expect(tf.from).to eq(start)
|
86
|
+
expect(tf.to).to eq(finish)
|
87
|
+
end
|
88
|
+
it 'should return a timeframe starting at constraint start' do
|
89
|
+
start = Date.parse('2008-01-01')
|
90
|
+
constraint_start = Date.parse('2008-01-14')
|
91
|
+
constraint = Timeframe.new(constraint_start, constraint_finish)
|
92
|
+
tf = Timeframe.constrained_new(start, finish, constraint)
|
93
|
+
expect(tf.from).to eq(constraint_start)
|
94
|
+
expect(tf.to).to eq(finish)
|
95
|
+
end
|
96
|
+
it 'should return a timeframe ending at constraint end' do
|
97
|
+
constraint_finish = Date.parse('2008-04-14')
|
98
|
+
constraint = Timeframe.new(constraint_start, constraint_finish)
|
99
|
+
tf = Timeframe.constrained_new(start, finish, constraint)
|
100
|
+
expect(tf.from).to eq(start)
|
101
|
+
expect(tf.to).to eq(constraint_finish)
|
102
|
+
end
|
103
|
+
it "should return a 0-length timeframe when constraining a timeframe by a disjoint timeframe" do
|
104
|
+
constraint = Timeframe.new :year => 2010
|
105
|
+
timeframe = Timeframe.constrained_new(
|
106
|
+
Date.new(2009,1,1), Date.new(2010,1,1), constraint)
|
107
|
+
expect(timeframe.days).to eq(0)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe :this_year do
|
112
|
+
it "should return the current year" do
|
113
|
+
expect(Timeframe.this_year).to eq(Timeframe.new(:year => Time.now.year))
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#days' do
|
118
|
+
it "should return them number of days included" do
|
119
|
+
#TODO: make these separate "it" blocks, per best practices
|
120
|
+
expect(Timeframe.new(Date.new(2007, 1, 1), Date.new(2008, 1, 1)).days).to eq(365)
|
121
|
+
expect(Timeframe.new(Date.new(2008, 1, 1), Date.new(2009, 1, 1)).days).to eq(366) # leap year
|
122
|
+
expect(Timeframe.new(Date.new(2007, 11, 1), Date.new(2007, 12, 1)).days).to eq(30)
|
123
|
+
expect(Timeframe.new(Date.new(2007, 11, 1), Date.new(2008, 1, 1)).days).to eq(61)
|
124
|
+
expect(Timeframe.new(Date.new(2007, 2, 1), Date.new(2007, 3, 1)).days).to eq(28)
|
125
|
+
expect(Timeframe.new(Date.new(2008, 2, 1), Date.new(2008, 3, 1)).days).to eq(29)
|
126
|
+
expect(Timeframe.new(Date.new(2008, 2, 1), Date.new(2008, 2, 1)).days).to eq(0)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '#include?' do
|
131
|
+
it "should know if a certain date is included in the Timeframe" do
|
132
|
+
#TODO: make these separate "it" blocks, per best practices
|
133
|
+
timeframe = Timeframe.new :year => 2008, :month => 2
|
134
|
+
[
|
135
|
+
Date.new(2008, 2, 1),
|
136
|
+
Date.new(2008, 2, 5),
|
137
|
+
Date.new(2008, 2, 29)
|
138
|
+
].each do |date|
|
139
|
+
expect(timeframe.include?(date)).to eq(true)
|
140
|
+
end
|
141
|
+
[
|
142
|
+
Date.new(2008, 1, 1),
|
143
|
+
Date.new(2007, 2, 1),
|
144
|
+
Date.new(2008, 3, 1)
|
145
|
+
].each do |date|
|
146
|
+
expect(timeframe.include?(date)).to eq(false)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe '#==' do
|
152
|
+
it "should be able to know if it's equal to another Timeframe object" do
|
153
|
+
expect(Timeframe.new(:year => 2007)).to eq(Timeframe.new(:year => 2007))
|
154
|
+
expect(Timeframe.new(:year => 2004, :month => 1)).to eq(Timeframe.new(:year => 2004, :month => 1))
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should hash equal hash values when the timeframe is equal" do
|
158
|
+
expect(Timeframe.new(:year => 2007).hash).to eq(Timeframe.new(:year => 2007).hash)
|
159
|
+
expect(Timeframe.new(:year => 2004, :month => 1).hash).to eq(Timeframe.new(:year => 2004, :month => 1).hash)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe '#months' do
|
164
|
+
it "should return an array of month-long subtimeframes" do
|
165
|
+
expect(Timeframe.new(:year => 2009).months.length).to eq(12)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe '#year' do
|
170
|
+
it "should return the relevant year of a timeframe" do
|
171
|
+
expect(Timeframe.new(Date.new(2009, 2, 1), Date.new(2009, 4, 1)).year).to eq(Timeframe.new(:year => 2009))
|
172
|
+
end
|
173
|
+
it "should not return the relevant year of a timeframe if provided an inappropriate range" do
|
174
|
+
expect {
|
175
|
+
Timeframe.new(Date.new(2009, 1, 1), Date.new(2012, 1, 1)).year
|
176
|
+
}.to raise_error(ArgumentError, /dangerous during/)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe '#&' do
|
181
|
+
it "should return its intersection with another timeframe" do
|
182
|
+
#TODO: make these separate "it" blocks, per best practices
|
183
|
+
expect(Timeframe.new(:month => 4) & Timeframe.new(:month => 6)).to be_nil
|
184
|
+
expect(Timeframe.new(:month => 4) & Timeframe.new(:month => 5)).to be_nil
|
185
|
+
expect((Timeframe.new(:month => 4) & Timeframe.new(:month => 4))).to eq(Timeframe.new(:month => 4))
|
186
|
+
expect((Timeframe.new(:year => Time.now.year) & Timeframe.new(:month => 4))).to eq(Timeframe.new(:month => 4))
|
187
|
+
expect((Timeframe.new(Date.new(2009, 2, 1), Date.new(2009, 6, 1)) & Timeframe.new(Date.new(2009, 4, 1), Date.new(2009, 8, 1)))).to eq(Timeframe.new(Date.new(2009, 4, 1), Date.new(2009, 6, 1)))
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
describe '#/' do
|
192
|
+
it "should return a fraction of another timeframe" do
|
193
|
+
expect(Timeframe.new(:month => 4, :year => 2009) / Timeframe.new(:year => 2009)).to eq(30.0 / 365.0)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
describe '#gaps_left_by' do
|
198
|
+
it "should be able to ascertain gaps left by a list of other Timeframes" do
|
199
|
+
expect(Timeframe.new(:year => 2009).gaps_left_by(
|
200
|
+
Timeframe.new(:year => 2009, :month => 3),
|
201
|
+
Timeframe.new(:year => 2009, :month => 5),
|
202
|
+
Timeframe.new(Date.new(2009, 8, 1), Date.new(2009, 11, 1)),
|
203
|
+
Timeframe.new(Date.new(2009, 9, 1), Date.new(2009, 10, 1))
|
204
|
+
)).to eq(
|
205
|
+
[ Timeframe.new(Date.new(2009, 1, 1), Date.new(2009, 3, 1)),
|
206
|
+
Timeframe.new(Date.new(2009, 4, 1), Date.new(2009, 5, 1)),
|
207
|
+
Timeframe.new(Date.new(2009, 6, 1), Date.new(2009, 8, 1)),
|
208
|
+
Timeframe.new(Date.new(2009, 11, 1), Date.new(2010, 1, 1)) ])
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe '#covered_by?' do
|
213
|
+
it "should be able to ascertain gaps left by a list of other Timeframes" do
|
214
|
+
expect(Timeframe.new(:year => 2009).covered_by?(
|
215
|
+
Timeframe.new(:month => 1, :year => 2009),
|
216
|
+
Timeframe.new(Date.new(2009, 2, 1), Date.new(2010, 1, 1))
|
217
|
+
)).to eq(true)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe '#last_year' do
|
222
|
+
it "should return its predecessor in a previous year" do
|
223
|
+
expect(Timeframe.this_year.last_year).to eq(Timeframe.new(Date.new(Date.today.year - 1, 1, 1), Date.new(Date.today.year, 1, 1)))
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
describe :parse do
|
228
|
+
describe 'ISO 8601 <start>/<end>' do
|
229
|
+
it 'works without time' do
|
230
|
+
expect(Timeframe.parse('2007-03-01/2008-05-11')).to eq(Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 5, 11)))
|
231
|
+
expect(Timeframe.parse('2007-03-01--2008-05-11')).to eq(Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 5, 11)))
|
232
|
+
end
|
233
|
+
it 'works with time' do
|
234
|
+
expect(Timeframe.parse('2007-03-01T13:00:00Z/2008-05-11T15:30:00Z')).to eq(Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 5, 11)))
|
235
|
+
expect(Timeframe.parse('2007-03-01T13:00:00Z--2008-05-11T15:30:00Z')).to eq(Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 5, 11)))
|
236
|
+
end
|
237
|
+
it 'takes shorthand' do
|
238
|
+
expect(Timeframe.parse('2007-11-13/15')).to eq(Timeframe.new(Date.new(2007, 11, 13), Date.new(2007, 11, 15))) # "2007-11-13/15", i.e. from any time on 2007-11-13 to any time on 2007-11-15
|
239
|
+
expect(Timeframe.parse("2008-02-15/03-14")).to eq(Timeframe.new(Date.new(2008, 2, 15), Date.new(2008, 3, 14))) # "2008-02-15/2008-03-14"
|
240
|
+
expect(Timeframe.parse("2007-12-14T13:30/15:30")).to eq(Timeframe.new(Date.new(2007, 12, 14), Date.new(2007, 12, 14))) # "2007-12-14T13:30/2007-12-14T15:30".. imprecise!
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe 'ISO 8601 <start>/<duration>' do
|
245
|
+
it 'works without time' do
|
246
|
+
expect(Timeframe.parse('2007-03-01/P1Y2M10DT2H30M')).to eq(Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 5, 11)))
|
247
|
+
expect(Timeframe.parse('2007-03-01--P1Y2M10DT2H30M')).to eq(Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 5, 11)))
|
248
|
+
end
|
249
|
+
it 'works with time' do
|
250
|
+
expect(Timeframe.parse('2007-03-01T13:00:00Z/P1Y2M10DT2H30M')).to eq(Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 5, 11)))
|
251
|
+
expect(Timeframe.parse('2007-03-01T13:00:00Z--P1Y2M10DT2H30M')).to eq(Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 5, 11)))
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# note that 2008 was a leap year
|
256
|
+
describe 'ISO 8601 <duration>/<end>' do
|
257
|
+
it 'works with leap years' do
|
258
|
+
expect(Timeframe.parse('2007-02-28--P1Y')).to eq(Timeframe.new(Date.new(2007, 2, 28), Date.new(2008, 2, 29)))
|
259
|
+
expect(Timeframe.parse('P1Y--2008-02-29')).to eq(Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 2, 29)))
|
260
|
+
end
|
261
|
+
it 'works without time' do
|
262
|
+
expect(Timeframe.parse('P1Y2M10DT2H30M/2008-05-11')).to eq(Timeframe.new(Date.new(2007, 3, 2), Date.new(2008, 5, 11)))
|
263
|
+
expect(Timeframe.parse('P1Y2M10DT2H30M--2008-05-11')).to eq(Timeframe.new(Date.new(2007, 3, 2), Date.new(2008, 5, 11)))
|
264
|
+
end
|
265
|
+
it 'works with time' do
|
266
|
+
expect(Timeframe.parse('P1Y2M10DT2H30M/2008-05-11T15:30:00Z')).to eq(Timeframe.new(Date.new(2007, 3, 3), Date.new(2008, 5, 11)))
|
267
|
+
expect(Timeframe.parse('P1Y2M10DT2H30M--2008-05-11T15:30:00Z')).to eq(Timeframe.new(Date.new(2007, 3, 3), Date.new(2008, 5, 11)))
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'understands plain year' do
|
272
|
+
plain_year = 2009
|
273
|
+
expect(Timeframe.parse(plain_year)).to eq(Timeframe.new(:year => plain_year))
|
274
|
+
expect(Timeframe.parse(plain_year.to_s)).to eq(Timeframe.new(:year => plain_year))
|
275
|
+
end
|
276
|
+
it 'understands JSON' do
|
277
|
+
json =<<-EOS
|
278
|
+
"2009-05-01/2009-06-01"
|
279
|
+
EOS
|
280
|
+
expect(Timeframe.parse(json)).to eq(Timeframe.new(:year => 2009, :month => 5))
|
281
|
+
end
|
282
|
+
it 'understands a particular style of Ruby hash we used to emit (deprecated)' do
|
283
|
+
hsh = { :startDate => '2009-05-01', :endDate => '2009-06-01' }
|
284
|
+
expect(Timeframe.parse(hsh)).to eq(Timeframe.new(:year => 2009, :month => 5))
|
285
|
+
expect(Timeframe.parse(hsh.stringify_keys)).to eq(Timeframe.new(:year => 2009, :month => 5))
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
describe '#as_json' do
|
290
|
+
it 'should generate JSON (test fails on ruby 1.8)' do
|
291
|
+
expect(Timeframe.new(:year => 2009).as_json).to eq(%{2009-01-01/2010-01-01})
|
292
|
+
expect(MultiJson.dump(Timeframe.new(:year => 2009))).to eq(Timeframe.new(:year => 2009).as_json.inspect)
|
293
|
+
end
|
294
|
+
it 'understands its own JSON' do
|
295
|
+
t = Timeframe.new(:year => 2009, :month => 5)
|
296
|
+
expect(Timeframe.from_json(MultiJson.dump(t))).to eq(t)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
describe '#to_param' do
|
301
|
+
it 'should generate a URL-friendly parameter' do
|
302
|
+
expect(Timeframe.new(:year => 2009).to_param).to eq("2009-01-01/2010-01-01")
|
303
|
+
end
|
304
|
+
it 'understands its own #to_param' do
|
305
|
+
t = Timeframe.new(:year => 2009, :month => 5)
|
306
|
+
expect(Timeframe.parse(t.to_param)).to eq(t)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
describe '#to_s' do
|
311
|
+
it 'should not only look at month numbers when describing multi-year timeframes' do
|
312
|
+
expect(Timeframe.new(Date.parse('2008-01-01'), Date.parse('2010-01-01')).to_s).to eq("2008-01-01/2010-01-01")
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
describe '#dates' do
|
317
|
+
it "should enumerate all dates between start and end" do
|
318
|
+
dates = Timeframe.new(:year => 2008).dates
|
319
|
+
expect(dates.min).to eq(Date.new(2008,1,1))
|
320
|
+
expect(dates.max).to eq(Date.new(2008,12,31))
|
321
|
+
expect(dates.uniq.length).to eq(366)
|
322
|
+
expect(dates.select { |d| d.month == 2 }.length).to eq(29)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
describe '#first_days_of_months' do
|
327
|
+
it "should enumerate all the first days of included months" do
|
328
|
+
dates = Timeframe.parse('2011-05-01/2012-02-01').first_days_of_months
|
329
|
+
expect(dates).to eq([Date.new(2011,5,1), Date.new(2011,6,1), Date.new(2011,7,1), Date.new(2011,8,1), Date.new(2011,9,1), Date.new(2011,10,1), Date.new(2011,11,1), Date.new(2011,12,1), Date.new(2012,1,1)])
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|
data/timeframe.gemspec
CHANGED
@@ -21,5 +21,8 @@ Gem::Specification.new do |s|
|
|
21
21
|
|
22
22
|
s.add_runtime_dependency 'activesupport', '>=2.3.5'
|
23
23
|
s.add_runtime_dependency 'i18n'
|
24
|
-
|
24
|
+
|
25
|
+
s.add_development_dependency "bundler"
|
26
|
+
s.add_development_dependency "rake"
|
27
|
+
s.add_development_dependency "rspec"
|
25
28
|
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: timeframe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Andy Rossmeissl
|
@@ -11,54 +10,76 @@ authors:
|
|
11
10
|
autorequire:
|
12
11
|
bindir: bin
|
13
12
|
cert_chain: []
|
14
|
-
date:
|
13
|
+
date: 2017-06-22 00:00:00.000000000 Z
|
15
14
|
dependencies:
|
16
15
|
- !ruby/object:Gem::Dependency
|
17
16
|
name: activesupport
|
18
17
|
requirement: !ruby/object:Gem::Requirement
|
19
|
-
none: false
|
20
18
|
requirements:
|
21
|
-
- -
|
19
|
+
- - ">="
|
22
20
|
- !ruby/object:Gem::Version
|
23
21
|
version: 2.3.5
|
24
22
|
type: :runtime
|
25
23
|
prerelease: false
|
26
24
|
version_requirements: !ruby/object:Gem::Requirement
|
27
|
-
none: false
|
28
25
|
requirements:
|
29
|
-
- -
|
26
|
+
- - ">="
|
30
27
|
- !ruby/object:Gem::Version
|
31
28
|
version: 2.3.5
|
32
29
|
- !ruby/object:Gem::Dependency
|
33
30
|
name: i18n
|
34
31
|
requirement: !ruby/object:Gem::Requirement
|
35
|
-
none: false
|
36
32
|
requirements:
|
37
|
-
- -
|
33
|
+
- - ">="
|
38
34
|
- !ruby/object:Gem::Version
|
39
35
|
version: '0'
|
40
36
|
type: :runtime
|
41
37
|
prerelease: false
|
42
38
|
version_requirements: !ruby/object:Gem::Requirement
|
43
|
-
none: false
|
44
39
|
requirements:
|
45
|
-
- -
|
40
|
+
- - ">="
|
46
41
|
- !ruby/object:Gem::Version
|
47
42
|
version: '0'
|
48
43
|
- !ruby/object:Gem::Dependency
|
49
|
-
name:
|
44
|
+
name: bundler
|
50
45
|
requirement: !ruby/object:Gem::Requirement
|
51
|
-
none: false
|
52
46
|
requirements:
|
53
|
-
- -
|
47
|
+
- - ">="
|
54
48
|
- !ruby/object:Gem::Version
|
55
49
|
version: '0'
|
56
|
-
type: :
|
50
|
+
type: :development
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: rake
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: rspec
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
type: :development
|
57
79
|
prerelease: false
|
58
80
|
version_requirements: !ruby/object:Gem::Requirement
|
59
|
-
none: false
|
60
81
|
requirements:
|
61
|
-
- -
|
82
|
+
- - ">="
|
62
83
|
- !ruby/object:Gem::Version
|
63
84
|
version: '0'
|
64
85
|
description: A Ruby class for describing and interacting with timeframes.
|
@@ -68,44 +89,41 @@ executables: []
|
|
68
89
|
extensions: []
|
69
90
|
extra_rdoc_files: []
|
70
91
|
files:
|
71
|
-
- .gitignore
|
92
|
+
- ".gitignore"
|
72
93
|
- CHANGELOG
|
73
94
|
- Gemfile
|
74
95
|
- LICENSE
|
75
96
|
- README.markdown
|
76
97
|
- Rakefile
|
77
98
|
- lib/timeframe.rb
|
78
|
-
- lib/timeframe/core_ext/array.rb
|
79
99
|
- lib/timeframe/iso_8601.rb
|
80
100
|
- lib/timeframe/version.rb
|
81
|
-
-
|
82
|
-
-
|
101
|
+
- spec/spec_helper.rb
|
102
|
+
- spec/timeframe_spec.rb
|
83
103
|
- timeframe.gemspec
|
84
104
|
homepage: http://github.com/rossmeissl/timeframe
|
85
105
|
licenses: []
|
106
|
+
metadata: {}
|
86
107
|
post_install_message:
|
87
108
|
rdoc_options: []
|
88
109
|
require_paths:
|
89
110
|
- lib
|
90
111
|
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
-
none: false
|
92
112
|
requirements:
|
93
|
-
- -
|
113
|
+
- - ">="
|
94
114
|
- !ruby/object:Gem::Version
|
95
115
|
version: '0'
|
96
116
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
117
|
requirements:
|
99
|
-
- -
|
118
|
+
- - ">="
|
100
119
|
- !ruby/object:Gem::Version
|
101
120
|
version: '0'
|
102
121
|
requirements: []
|
103
122
|
rubyforge_project: timeframe
|
104
|
-
rubygems_version:
|
123
|
+
rubygems_version: 2.6.8
|
105
124
|
signing_key:
|
106
|
-
specification_version:
|
125
|
+
specification_version: 4
|
107
126
|
summary: Date intervals
|
108
127
|
test_files:
|
109
|
-
-
|
110
|
-
-
|
111
|
-
has_rdoc:
|
128
|
+
- spec/spec_helper.rb
|
129
|
+
- spec/timeframe_spec.rb
|
@@ -1,9 +0,0 @@
|
|
1
|
-
class Array
|
2
|
-
# Constructs an array of timeframes representing the "gaps" left by the given array of timeframes.
|
3
|
-
#
|
4
|
-
# To use this feature, you must explicitly require 'timeframe/core_ext/array'
|
5
|
-
def multiple_timeframes_gaps_left_by(*time_frames)
|
6
|
-
raise ArgumentError.new 'You can only use timeframe for this operation' unless [self + time_frames].flatten.all?{|el| el.is_a?(Timeframe)}
|
7
|
-
self.inject([]){|a,b| a << b.gaps_left_by(*time_frames)}.flatten
|
8
|
-
end
|
9
|
-
end
|
data/test/helper.rb
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'bundler/setup'
|
3
|
-
|
4
|
-
require 'minitest/spec'
|
5
|
-
require 'minitest/autorun'
|
6
|
-
require 'minitest/reporters'
|
7
|
-
MiniTest::Unit.runner = MiniTest::SuiteRunner.new
|
8
|
-
MiniTest::Unit.runner.reporters << MiniTest::Reporters::SpecReporter.new
|
9
|
-
|
10
|
-
require 'timeframe'
|
11
|
-
require 'timeframe/core_ext/array'
|
data/test/test_timeframe.rb
DELETED
@@ -1,354 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe Timeframe do
|
4
|
-
describe 'initialization' do
|
5
|
-
it 'should create a timeframe using date strings' do
|
6
|
-
tf = Timeframe.new('2008-02-14', '2008-05-10')
|
7
|
-
tf.from.must_equal Date.parse('2008-02-14')
|
8
|
-
tf.to.must_equal Date.parse('2008-05-10')
|
9
|
-
end
|
10
|
-
it 'should create a timeframe using date objects' do
|
11
|
-
start = Date.parse('2008-02-14')
|
12
|
-
finish = Date.parse('2008-05-10')
|
13
|
-
tf = Timeframe.new(start, finish)
|
14
|
-
tf.from.must_equal start
|
15
|
-
tf.to.must_equal finish
|
16
|
-
end
|
17
|
-
it "should accept months" do
|
18
|
-
timeframe = Timeframe.new(:month => 1)
|
19
|
-
timeframe.from.must_equal Date.today.change(:month => 1, :day => 1)
|
20
|
-
timeframe.to.must_equal Date.today.change(:month => 2, :day => 1)
|
21
|
-
end
|
22
|
-
it "should accept month names" do
|
23
|
-
timeframe = Timeframe.new(:month => 'february')
|
24
|
-
timeframe.from.must_equal Date.today.change(:month => 2, :day => 1)
|
25
|
-
timeframe.to.must_equal Date.today.change(:month => 3, :day => 1)
|
26
|
-
end
|
27
|
-
it "should accept years" do
|
28
|
-
timeframe = Timeframe.new(:year => 2004)
|
29
|
-
timeframe.from.must_equal Date.new(2004, 1, 1)
|
30
|
-
timeframe.to.must_equal Date.new(2005, 1, 1)
|
31
|
-
end
|
32
|
-
it "should accept years and months" do
|
33
|
-
timeframe = Timeframe.new(:year => 2005, :month => 5)
|
34
|
-
timeframe.from.must_equal Date.new(2005, 5, 1)
|
35
|
-
timeframe.to.must_equal Date.new(2005, 6, 1)
|
36
|
-
end
|
37
|
-
it "should not accept just one date argument" do
|
38
|
-
lambda {
|
39
|
-
Timeframe.new Date.new(2007, 2, 1)
|
40
|
-
}.must_raise(ArgumentError, /supply/)
|
41
|
-
end
|
42
|
-
it "should not accept end date that is earlier than start date" do
|
43
|
-
lambda {
|
44
|
-
timeframe = Timeframe.new Date.new(2008, 1, 1), Date.new(2007, 1, 1)
|
45
|
-
}.must_raise(ArgumentError, /earlier/)
|
46
|
-
end
|
47
|
-
it "should always accept timeframes that cross year boundaries" do
|
48
|
-
timeframe = Timeframe.new Date.new(2007, 1, 1), Date.new(2008, 1, 2)
|
49
|
-
timeframe.start_date.must_equal Date.new(2007, 1, 1)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
describe '#inspect' do
|
54
|
-
it 'should return the time frame in readable text' do
|
55
|
-
start = Date.parse('2008-02-14')
|
56
|
-
finish = Date.parse('2008-05-10')
|
57
|
-
tf = Timeframe.new(start, finish)
|
58
|
-
tf.inspect.must_match %r{<Timeframe\(-?\d+\) 86 days starting 2008-02-14 ending 2008-05-10>}
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
describe :constrained_new do
|
63
|
-
let(:start) { Date.parse('2008-02-14') }
|
64
|
-
let(:finish) { Date.parse('2008-05-10') }
|
65
|
-
let(:constraint_start) { Date.parse('2008-01-01') }
|
66
|
-
let(:constraint_finish) { Date.parse('2008-12-01') }
|
67
|
-
let(:constraint) { Timeframe.new(constraint_start, constraint_finish) }
|
68
|
-
|
69
|
-
it "should allow for constrained creation" do
|
70
|
-
constraint = Timeframe.new :year => 2008
|
71
|
-
may = Timeframe.new Date.new(2008,5,1), Date.new(2008,6,1)
|
72
|
-
january = Timeframe.new Date.new(2008,1,1), Date.new(2008,2,1)
|
73
|
-
Timeframe.constrained_new(may.from, may.to, constraint).must_equal may
|
74
|
-
Timeframe.constrained_new(Date.new(2007,1,1), Date.new(2010,1,1), constraint).must_equal constraint
|
75
|
-
Timeframe.constrained_new(Date.new(2007,11,1), Date.new(2008,2,1), constraint).must_equal january
|
76
|
-
end
|
77
|
-
it 'should return a timeframe spanning start and end date if within constraint' do
|
78
|
-
tf = Timeframe.constrained_new(start, finish, constraint)
|
79
|
-
tf.from.must_equal start
|
80
|
-
tf.to.must_equal finish
|
81
|
-
end
|
82
|
-
it 'should return a timeframe spanning constraint start and end date if outside constraint' do
|
83
|
-
constraint = Timeframe.new(start, finish)
|
84
|
-
tf = Timeframe.constrained_new(constraint_start, constraint_finish, constraint)
|
85
|
-
tf.from.must_equal start
|
86
|
-
tf.to.must_equal finish
|
87
|
-
end
|
88
|
-
it 'should return a timeframe starting at constraint start' do
|
89
|
-
start = Date.parse('2008-01-01')
|
90
|
-
constraint_start = Date.parse('2008-01-14')
|
91
|
-
constraint = Timeframe.new(constraint_start, constraint_finish)
|
92
|
-
tf = Timeframe.constrained_new(start, finish, constraint)
|
93
|
-
tf.from.must_equal constraint_start
|
94
|
-
tf.to.must_equal finish
|
95
|
-
end
|
96
|
-
it 'should return a timeframe ending at constraint end' do
|
97
|
-
constraint_finish = Date.parse('2008-04-14')
|
98
|
-
constraint = Timeframe.new(constraint_start, constraint_finish)
|
99
|
-
tf = Timeframe.constrained_new(start, finish, constraint)
|
100
|
-
tf.from.must_equal start
|
101
|
-
tf.to.must_equal constraint_finish
|
102
|
-
end
|
103
|
-
it "should return a 0-length timeframe when constraining a timeframe by a disjoint timeframe" do
|
104
|
-
constraint = Timeframe.new :year => 2010
|
105
|
-
timeframe = Timeframe.constrained_new(
|
106
|
-
Date.new(2009,1,1), Date.new(2010,1,1), constraint)
|
107
|
-
timeframe.days.must_equal 0
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
describe :this_year do
|
112
|
-
it "should return the current year" do
|
113
|
-
Timeframe.this_year.must_equal Timeframe.new(:year => Time.now.year)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
describe '#days' do
|
118
|
-
it "should return them number of days included" do
|
119
|
-
#TODO: make these separate "it" blocks, per best practices
|
120
|
-
Timeframe.new(Date.new(2007, 1, 1), Date.new(2008, 1, 1)).days.must_equal 365
|
121
|
-
Timeframe.new(Date.new(2008, 1, 1), Date.new(2009, 1, 1)).days.must_equal 366 #leap year
|
122
|
-
Timeframe.new(Date.new(2007, 11, 1), Date.new(2007, 12, 1)).days.must_equal 30
|
123
|
-
Timeframe.new(Date.new(2007, 11, 1), Date.new(2008, 1, 1)).days.must_equal 61
|
124
|
-
Timeframe.new(Date.new(2007, 2, 1), Date.new(2007, 3, 1)).days.must_equal 28
|
125
|
-
Timeframe.new(Date.new(2008, 2, 1), Date.new(2008, 3, 1)).days.must_equal 29
|
126
|
-
Timeframe.new(Date.new(2008, 2, 1), Date.new(2008, 2, 1)).days.must_equal 0
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
describe '#include?' do
|
131
|
-
it "should know if a certain date is included in the Timeframe" do
|
132
|
-
#TODO: make these separate "it" blocks, per best practices
|
133
|
-
timeframe = Timeframe.new :year => 2008, :month => 2
|
134
|
-
[
|
135
|
-
Date.new(2008, 2, 1),
|
136
|
-
Date.new(2008, 2, 5),
|
137
|
-
Date.new(2008, 2, 29)
|
138
|
-
].each do |date|
|
139
|
-
timeframe.include?(date).must_equal true
|
140
|
-
end
|
141
|
-
[
|
142
|
-
Date.new(2008, 1, 1),
|
143
|
-
Date.new(2007, 2, 1),
|
144
|
-
Date.new(2008, 3, 1)
|
145
|
-
].each do |date|
|
146
|
-
timeframe.include?(date).must_equal false
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
describe '#==' do
|
152
|
-
it "should be able to know if it's equal to another Timeframe object" do
|
153
|
-
Timeframe.new(:year => 2007).must_equal Timeframe.new(:year => 2007)
|
154
|
-
Timeframe.new(:year => 2004, :month => 1).must_equal Timeframe.new(:year => 2004, :month => 1)
|
155
|
-
end
|
156
|
-
|
157
|
-
it "should hash equal hash values when the timeframe is equal" do
|
158
|
-
Timeframe.new(:year => 2007).hash.must_equal Timeframe.new(:year => 2007).hash
|
159
|
-
Timeframe.new(:year => 2004, :month => 1).hash.must_equal Timeframe.new(:year => 2004, :month => 1).hash
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
describe '#months' do
|
164
|
-
it "should return an array of month-long subtimeframes" do
|
165
|
-
Timeframe.new(:year => 2009).months.length.must_equal 12
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
describe '#year' do
|
170
|
-
it "should return the relevant year of a timeframe" do
|
171
|
-
Timeframe.new(Date.new(2009, 2, 1), Date.new(2009, 4, 1)).year.must_equal Timeframe.new(:year => 2009)
|
172
|
-
end
|
173
|
-
it "should not return the relevant year of a timeframe if provided an inappropriate range" do
|
174
|
-
lambda {
|
175
|
-
Timeframe.new(Date.new(2009, 1, 1), Date.new(2012, 1, 1)).year
|
176
|
-
}.must_raise(ArgumentError, /dangerous during/)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
describe '#&' do
|
181
|
-
it "should return its intersection with another timeframe" do
|
182
|
-
#TODO: make these separate "it" blocks, per best practices
|
183
|
-
(Timeframe.new(:month => 4) & Timeframe.new(:month => 6)).must_be_nil
|
184
|
-
(Timeframe.new(:month => 4) & Timeframe.new(:month => 5)).must_be_nil
|
185
|
-
(Timeframe.new(:month => 4) & Timeframe.new(:month => 4)).must_equal Timeframe.new(:month => 4)
|
186
|
-
(Timeframe.new(:year => Time.now.year) & Timeframe.new(:month => 4)).must_equal Timeframe.new(:month => 4)
|
187
|
-
(Timeframe.new(Date.new(2009, 2, 1), Date.new(2009, 6, 1)) & Timeframe.new(Date.new(2009, 4, 1), Date.new(2009, 8, 1))).must_equal Timeframe.new(Date.new(2009, 4, 1), Date.new(2009, 6, 1))
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
describe '#/' do
|
192
|
-
it "should return a fraction of another timeframe" do
|
193
|
-
(Timeframe.new(:month => 4, :year => 2009) / Timeframe.new(:year => 2009)).must_equal(30.0 / 365.0)
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
describe '#gaps_left_by' do
|
198
|
-
it "should be able to ascertain gaps left by a list of other Timeframes" do
|
199
|
-
Timeframe.new(:year => 2009).gaps_left_by(
|
200
|
-
Timeframe.new(:year => 2009, :month => 3),
|
201
|
-
Timeframe.new(:year => 2009, :month => 5),
|
202
|
-
Timeframe.new(Date.new(2009, 8, 1), Date.new(2009, 11, 1)),
|
203
|
-
Timeframe.new(Date.new(2009, 9, 1), Date.new(2009, 10, 1))
|
204
|
-
).must_equal(
|
205
|
-
[ Timeframe.new(Date.new(2009, 1, 1), Date.new(2009, 3, 1)),
|
206
|
-
Timeframe.new(Date.new(2009, 4, 1), Date.new(2009, 5, 1)),
|
207
|
-
Timeframe.new(Date.new(2009, 6, 1), Date.new(2009, 8, 1)),
|
208
|
-
Timeframe.new(Date.new(2009, 11, 1), Date.new(2010, 1, 1)) ])
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
describe '#covered_by?' do
|
213
|
-
it "should be able to ascertain gaps left by a list of other Timeframes" do
|
214
|
-
Timeframe.new(:year => 2009).covered_by?(
|
215
|
-
Timeframe.new(:month => 1, :year => 2009),
|
216
|
-
Timeframe.new(Date.new(2009, 2, 1), Date.new(2010, 1, 1))
|
217
|
-
).must_equal(true)
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
describe '#last_year' do
|
222
|
-
it "should return its predecessor in a previous year" do
|
223
|
-
Timeframe.this_year.last_year.must_equal Timeframe.new(Date.new(Date.today.year - 1, 1, 1), Date.new(Date.today.year, 1, 1))
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
describe :parse do
|
228
|
-
describe 'ISO 8601 <start>/<end>' do
|
229
|
-
it 'works without time' do
|
230
|
-
Timeframe.parse('2007-03-01/2008-05-11').must_equal Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 5, 11))
|
231
|
-
Timeframe.parse('2007-03-01--2008-05-11').must_equal Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 5, 11))
|
232
|
-
end
|
233
|
-
it 'works with time' do
|
234
|
-
Timeframe.parse('2007-03-01T13:00:00Z/2008-05-11T15:30:00Z').must_equal Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 5, 11))
|
235
|
-
Timeframe.parse('2007-03-01T13:00:00Z--2008-05-11T15:30:00Z').must_equal Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 5, 11))
|
236
|
-
end
|
237
|
-
it 'takes shorthand' do
|
238
|
-
Timeframe.parse('2007-11-13/15').must_equal Timeframe.new(Date.new(2007, 11, 13), Date.new(2007, 11, 15)) # "2007-11-13/15", i.e. from any time on 2007-11-13 to any time on 2007-11-15
|
239
|
-
Timeframe.parse("2008-02-15/03-14").must_equal Timeframe.new(Date.new(2008, 2, 15), Date.new(2008, 3, 14)) # "2008-02-15/2008-03-14"
|
240
|
-
Timeframe.parse("2007-12-14T13:30/15:30").must_equal Timeframe.new(Date.new(2007, 12, 14), Date.new(2007, 12, 14)) # "2007-12-14T13:30/2007-12-14T15:30".. imprecise!
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
describe 'ISO 8601 <start>/<duration>' do
|
245
|
-
it 'works without time' do
|
246
|
-
Timeframe.parse('2007-03-01/P1Y2M10DT2H30M').must_equal Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 5, 11))
|
247
|
-
Timeframe.parse('2007-03-01--P1Y2M10DT2H30M').must_equal Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 5, 11))
|
248
|
-
end
|
249
|
-
it 'works with time' do
|
250
|
-
Timeframe.parse('2007-03-01T13:00:00Z/P1Y2M10DT2H30M').must_equal Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 5, 11))
|
251
|
-
Timeframe.parse('2007-03-01T13:00:00Z--P1Y2M10DT2H30M').must_equal Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 5, 11))
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
# note that 2008 was a leap year
|
256
|
-
describe 'ISO 8601 <duration>/<end>' do
|
257
|
-
it 'works with leap years' do
|
258
|
-
Timeframe.parse('2007-02-28--P1Y').must_equal Timeframe.new(Date.new(2007, 2, 28), Date.new(2008, 2, 29))
|
259
|
-
Timeframe.parse('P1Y--2008-02-29').must_equal Timeframe.new(Date.new(2007, 3, 1), Date.new(2008, 2, 29))
|
260
|
-
end
|
261
|
-
it 'works without time' do
|
262
|
-
Timeframe.parse('P1Y2M10DT2H30M/2008-05-11').must_equal Timeframe.new(Date.new(2007, 3, 2), Date.new(2008, 5, 11))
|
263
|
-
Timeframe.parse('P1Y2M10DT2H30M--2008-05-11').must_equal Timeframe.new(Date.new(2007, 3, 2), Date.new(2008, 5, 11))
|
264
|
-
end
|
265
|
-
it 'works with time' do
|
266
|
-
Timeframe.parse('P1Y2M10DT2H30M/2008-05-11T15:30:00Z').must_equal Timeframe.new(Date.new(2007, 3, 3), Date.new(2008, 5, 11))
|
267
|
-
Timeframe.parse('P1Y2M10DT2H30M--2008-05-11T15:30:00Z').must_equal Timeframe.new(Date.new(2007, 3, 3), Date.new(2008, 5, 11))
|
268
|
-
end
|
269
|
-
end
|
270
|
-
|
271
|
-
it 'understands plain year' do
|
272
|
-
plain_year = 2009
|
273
|
-
Timeframe.parse(plain_year).must_equal Timeframe.new(:year => plain_year)
|
274
|
-
Timeframe.parse(plain_year.to_s).must_equal Timeframe.new(:year => plain_year)
|
275
|
-
end
|
276
|
-
it 'understands JSON' do
|
277
|
-
json =<<-EOS
|
278
|
-
"2009-05-01/2009-06-01"
|
279
|
-
EOS
|
280
|
-
Timeframe.parse(json).must_equal Timeframe.new(:year => 2009, :month => 5)
|
281
|
-
end
|
282
|
-
it 'understands a particular style of Ruby hash we used to emit (deprecated)' do
|
283
|
-
hsh = { :startDate => '2009-05-01', :endDate => '2009-06-01' }
|
284
|
-
Timeframe.parse(hsh).must_equal Timeframe.new(:year => 2009, :month => 5)
|
285
|
-
Timeframe.parse(hsh.stringify_keys).must_equal Timeframe.new(:year => 2009, :month => 5)
|
286
|
-
end
|
287
|
-
end
|
288
|
-
|
289
|
-
describe '#as_json' do
|
290
|
-
it 'should generate JSON (test fails on ruby 1.8)' do
|
291
|
-
Timeframe.new(:year => 2009).as_json.must_equal %{2009-01-01/2010-01-01}
|
292
|
-
MultiJson.dump(Timeframe.new(:year => 2009)).must_equal Timeframe.new(:year => 2009).as_json.inspect
|
293
|
-
end
|
294
|
-
it 'understands its own JSON' do
|
295
|
-
t = Timeframe.new(:year => 2009, :month => 5)
|
296
|
-
Timeframe.from_json(MultiJson.dump(t)).must_equal t
|
297
|
-
end
|
298
|
-
end
|
299
|
-
|
300
|
-
describe '#to_param' do
|
301
|
-
it 'should generate a URL-friendly parameter' do
|
302
|
-
Timeframe.new(:year => 2009).to_param.must_equal "2009-01-01/2010-01-01"
|
303
|
-
end
|
304
|
-
it 'understands its own #to_param' do
|
305
|
-
t = Timeframe.new(:year => 2009, :month => 5)
|
306
|
-
Timeframe.parse(t.to_param).must_equal t
|
307
|
-
end
|
308
|
-
end
|
309
|
-
|
310
|
-
describe '#to_s' do
|
311
|
-
it 'should not only look at month numbers when describing multi-year timeframes' do
|
312
|
-
Timeframe.new(Date.parse('2008-01-01'), Date.parse('2010-01-01')).to_s.must_equal "2008-01-01/2010-01-01"
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
describe '#dates' do
|
317
|
-
it "should enumerate all dates between start and end" do
|
318
|
-
dates = Timeframe.new(:year => 2008).dates
|
319
|
-
dates.min.must_equal Date.new(2008,1,1)
|
320
|
-
dates.max.must_equal Date.new(2008,12,31)
|
321
|
-
dates.uniq.length.must_equal 366
|
322
|
-
dates.select { |d| d.month == 2 }.length.must_equal 29
|
323
|
-
end
|
324
|
-
end
|
325
|
-
|
326
|
-
describe '#first_days_of_months' do
|
327
|
-
it "should enumerate all the first days of included months" do
|
328
|
-
dates = Timeframe.parse('2011-05-01/2012-02-01').first_days_of_months
|
329
|
-
dates.must_equal [Date.new(2011,5,1), Date.new(2011,6,1), Date.new(2011,7,1), Date.new(2011,8,1), Date.new(2011,9,1), Date.new(2011,10,1), Date.new(2011,11,1), Date.new(2011,12,1), Date.new(2012,1,1)]
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
describe "Array#multiple_timeframes_gaps_left_by" do
|
334
|
-
it "should raise error if not a Timeframes are going to be merged" do
|
335
|
-
lambda {
|
336
|
-
[Timeframe.new(Date.parse('2011-10-10'), Date.parse('2011-10-28'))].multiple_timeframes_gaps_left_by(1,2)
|
337
|
-
}.must_raise(ArgumentError, /only use timeframe/)
|
338
|
-
end
|
339
|
-
|
340
|
-
it "should properly work with multiple timeframes" do
|
341
|
-
t1 = Timeframe.new(Date.parse('2011-10-10'), Date.parse('2011-10-28'))
|
342
|
-
t2 = Timeframe.new(Date.parse('2011-11-01'), Date.parse('2011-11-12'))
|
343
|
-
|
344
|
-
t3 = Timeframe.new(Date.parse('2011-10-11'), Date.parse('2011-10-15'))
|
345
|
-
t4 = Timeframe.new(Date.parse('2011-11-01'), Date.parse('2011-11-08'))
|
346
|
-
|
347
|
-
[t1, t2].multiple_timeframes_gaps_left_by(t3, t4).must_equal(
|
348
|
-
[ Timeframe.new(Date.parse('2011-10-10'), Date.parse('2011-10-11')),
|
349
|
-
Timeframe.new(Date.parse('2011-10-15'), Date.parse('2011-10-28')),
|
350
|
-
Timeframe.new(Date.parse('2011-11-08'), Date.parse('2011-11-12'))
|
351
|
-
])
|
352
|
-
end
|
353
|
-
end
|
354
|
-
end
|