timeframe 0.2.1 → 1.0.0
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/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
|