time_frame 0.6.1 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -1
- data/lib/time_frame.rb +1 -1
- data/lib/time_frame/time_frame.rb +26 -18
- data/lib/time_frame/time_frame_overlaps.rb +1 -1
- data/lib/time_frame/{time_frame_handler.rb → time_frame_predicate_builder_handler.rb} +4 -7
- data/lib/time_frame/version.rb +1 -1
- data/spec/collection_spec.rb +1 -3
- data/spec/time_frame_predicate_builder_handler_spec.rb +41 -0
- data/spec/time_frame_spec.rb +7 -12
- data/time_frame.gemspec +6 -6
- metadata +17 -17
- data/spec/time_frame_handler_spec.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46d453a744497db5265eff93a9c51b5dae6dad53
|
4
|
+
data.tar.gz: 0638ebac436ed0d318e36dcc10e7d9fd9dfa4c0a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 44a1dcdaa9100b07e263ded5a781f9d62ceacb812e7ce494aed9e362e5f817e2b9ebd0b04267bad856cd4a7dbc0dd27252153254fae7e307db1cd20507ef1c9b
|
7
|
+
data.tar.gz: e5ddb3de3a236f3b2c0359c35b4fb30a0373d4d75acf07109fe8b9e6bffe704cc5880d8efa720a7be09918e978367f5e497be2ccd43c20bdb4a011a45d034b7f
|
data/.rubocop.yml
CHANGED
data/lib/time_frame.rb
CHANGED
@@ -10,7 +10,7 @@ require 'time_frame/time_frame_overlaps'
|
|
10
10
|
require 'time_frame/time_frame_uniter'
|
11
11
|
|
12
12
|
require 'time_frame/time_frame'
|
13
|
-
require 'time_frame/
|
13
|
+
require 'time_frame/time_frame_predicate_builder_handler'
|
14
14
|
|
15
15
|
require 'time_frame/tree_node'
|
16
16
|
require 'time_frame/collection'
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# Encoding: utf-8
|
2
2
|
|
3
3
|
# Temporary disable class length cop.
|
4
|
-
# rubocop:disable
|
4
|
+
# rubocop:disable Metrics/ClassLength
|
5
5
|
|
6
6
|
# The time frame class provides an specialized and enhanced range for time
|
7
7
|
# values.
|
@@ -24,7 +24,7 @@ class TimeFrame
|
|
24
24
|
|
25
25
|
def ==(other)
|
26
26
|
@min_float == other.min_float &&
|
27
|
-
|
27
|
+
@max_float == other.max_float
|
28
28
|
end
|
29
29
|
|
30
30
|
def <=>(other)
|
@@ -40,7 +40,7 @@ class TimeFrame
|
|
40
40
|
def cover?(element)
|
41
41
|
if element.is_a?(TimeFrame)
|
42
42
|
element.empty? ||
|
43
|
-
|
43
|
+
@min_float <= element.min_float && element.max_float <= max_float
|
44
44
|
else
|
45
45
|
min_float <= element.to_f && element.to_f <= max_float
|
46
46
|
end
|
@@ -69,13 +69,11 @@ class TimeFrame
|
|
69
69
|
def time_between(item)
|
70
70
|
case
|
71
71
|
when item.is_a?(TimeFrame)
|
72
|
-
|
73
|
-
[time_between(item.min), time_between(item.max)].min_by(&:abs)
|
72
|
+
time_between_time_frame(item)
|
74
73
|
when cover?(item)
|
75
74
|
0
|
76
75
|
else
|
77
|
-
|
78
|
-
[(float_value - min_float).abs, (float_value - max_float).abs].min
|
76
|
+
time_between_float(item.to_f)
|
79
77
|
end
|
80
78
|
end
|
81
79
|
|
@@ -134,7 +132,7 @@ class TimeFrame
|
|
134
132
|
|
135
133
|
def self.each_overlap(frames1, frames2)
|
136
134
|
Overlaps.new(frames1, frames2).each do |first, second|
|
137
|
-
yield
|
135
|
+
yield first, second
|
138
136
|
end
|
139
137
|
end
|
140
138
|
|
@@ -144,31 +142,41 @@ class TimeFrame
|
|
144
142
|
|
145
143
|
protected
|
146
144
|
|
147
|
-
|
148
|
-
intersection = self & other
|
145
|
+
attr_reader :min_float, :max_float
|
149
146
|
|
147
|
+
def without_frame(other)
|
150
148
|
result = []
|
151
|
-
|
152
|
-
|
149
|
+
|
150
|
+
if other.min_float > min_float
|
151
|
+
result << TimeFrame.new(min: min, max: other.min)
|
153
152
|
end
|
154
|
-
|
155
|
-
|
153
|
+
|
154
|
+
if other.max_float < max_float
|
155
|
+
result << TimeFrame.new(min: other.max, max: max)
|
156
156
|
end
|
157
|
+
|
157
158
|
result
|
158
159
|
end
|
159
160
|
|
160
|
-
attr_reader :min_float, :max_float
|
161
|
-
|
162
161
|
private
|
163
162
|
|
164
163
|
def fail_if_empty(item)
|
165
164
|
fail ArgumentError, 'time frame is empty' if item.respond_to?(:empty?) &&
|
166
|
-
|
165
|
+
item.empty?
|
167
166
|
end
|
168
167
|
|
169
168
|
def check_bounds
|
170
169
|
fail ArgumentError, 'min is greater than max.' if min > max
|
171
170
|
end
|
171
|
+
|
172
|
+
def time_between_time_frame(time_frame)
|
173
|
+
fail_if_empty time_frame
|
174
|
+
[time_between(time_frame.min), time_between(time_frame.max)].min_by(&:abs)
|
175
|
+
end
|
176
|
+
|
177
|
+
def time_between_float(float_value)
|
178
|
+
[(float_value - min_float).abs, (float_value - max_float).abs].min
|
179
|
+
end
|
172
180
|
end
|
173
181
|
|
174
|
-
# rubocop:enable
|
182
|
+
# rubocop:enable Metrics/ClassLength
|
@@ -1,16 +1,13 @@
|
|
1
1
|
class TimeFrame
|
2
2
|
# This class tells the active_record predicate builder how to handle
|
3
3
|
# time_frame classes when passed into a where-clause
|
4
|
-
class
|
4
|
+
class PredicateBuilderHandler
|
5
5
|
def call(column, time_frame)
|
6
|
-
|
7
|
-
column,
|
8
|
-
Arel::Nodes::And.new([time_frame.min, time_frame.max])
|
9
|
-
)
|
6
|
+
column.in(time_frame.min..time_frame.max)
|
10
7
|
end
|
11
8
|
end
|
12
9
|
end
|
13
10
|
|
14
11
|
ActiveRecord::PredicateBuilder.register_handler(
|
15
|
-
|
16
|
-
|
12
|
+
TimeFrame, TimeFrame::PredicateBuilderHandler.new
|
13
|
+
)
|
data/lib/time_frame/version.rb
CHANGED
data/spec/collection_spec.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe TimeFrame::Collection do
|
4
|
-
|
5
4
|
let(:time_frame) { TimeFrame.new(min: Time.utc(2014), duration: 20.days) }
|
6
5
|
let(:time) { Time.utc(2014) }
|
7
6
|
|
@@ -10,7 +9,7 @@ describe TimeFrame::Collection do
|
|
10
9
|
time_frames = 20.times.map { |i| time_frame.shift_by((5 * i).days) }
|
11
10
|
objects = time_frames.map { |tf| OpenStruct.new(interval: tf) }
|
12
11
|
tree = TimeFrame::Collection.new(objects) { |o| o.interval }
|
13
|
-
expect(tree.map
|
12
|
+
expect(tree.map(&:interval)).to eq time_frames
|
14
13
|
end
|
15
14
|
end
|
16
15
|
|
@@ -202,7 +201,6 @@ describe TimeFrame::Collection do
|
|
202
201
|
|
203
202
|
result = tree.all_intersecting(interval.shift_by(300.days))
|
204
203
|
expect(result).to eq []
|
205
|
-
|
206
204
|
end
|
207
205
|
end
|
208
206
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'models/vogon_poem'
|
3
|
+
|
4
|
+
describe TimeFrame::PredicateBuilderHandler do
|
5
|
+
let(:time_frame) { TimeFrame.new(min: 5.days.ago, duration: 20.days) }
|
6
|
+
|
7
|
+
before { VogonPoem.delete_all }
|
8
|
+
|
9
|
+
it 'returns all records between min and max' do
|
10
|
+
poem_min = VogonPoem.create(written_at: time_frame.min)
|
11
|
+
poem_max = VogonPoem.create(written_at: time_frame.max)
|
12
|
+
|
13
|
+
result = VogonPoem.where(written_at: time_frame)
|
14
|
+
|
15
|
+
expect(result.count).to eq 2
|
16
|
+
expect(result.first).to eq poem_min
|
17
|
+
expect(result.last).to eq poem_max
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'ignores records outside of min and max' do
|
21
|
+
poem_min = VogonPoem.create(written_at: time_frame.min + 1.minute)
|
22
|
+
VogonPoem.create(written_at: time_frame.min - 2.years)
|
23
|
+
VogonPoem.create(written_at: time_frame.max + 1.month)
|
24
|
+
|
25
|
+
result = VogonPoem.where(written_at: time_frame)
|
26
|
+
|
27
|
+
expect(result.count).to eq 1
|
28
|
+
expect(result.first).to eq poem_min
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'handles items close to the borders correctly' do
|
32
|
+
poem_min = VogonPoem.create(written_at: time_frame.min + 1.second)
|
33
|
+
VogonPoem.create(written_at: time_frame.min - 1.second)
|
34
|
+
VogonPoem.create(written_at: time_frame.max + 1.second)
|
35
|
+
|
36
|
+
result = VogonPoem.where(written_at: time_frame)
|
37
|
+
|
38
|
+
expect(result.count).to eq 1
|
39
|
+
expect(result.first).to eq poem_min
|
40
|
+
end
|
41
|
+
end
|
data/spec/time_frame_spec.rb
CHANGED
@@ -10,12 +10,12 @@ describe TimeFrame do
|
|
10
10
|
I18n.enforce_available_locales = true
|
11
11
|
end
|
12
12
|
|
13
|
-
it '
|
13
|
+
it 'is hashable' do
|
14
14
|
hash = {}
|
15
15
|
time_frame1 = TimeFrame.new(min: time, duration: duration)
|
16
16
|
time_frame2 = TimeFrame.new(min: time, duration: duration)
|
17
17
|
time_frame3 = TimeFrame.new(min: time, duration: duration / 2)
|
18
|
-
time_frame4 = TimeFrame.new(min: time - duration / 2
|
18
|
+
time_frame4 = TimeFrame.new(min: time - duration / 2, max: time + duration)
|
19
19
|
hash[time_frame1] = 1
|
20
20
|
expect(hash[time_frame2]).to eq 1
|
21
21
|
expect(hash[time_frame3]).not_to eq 1
|
@@ -92,14 +92,13 @@ describe TimeFrame do
|
|
92
92
|
|
93
93
|
context 'when min is a date' do
|
94
94
|
context 'and duration is 0' do
|
95
|
-
it '
|
95
|
+
it 'is valid' do
|
96
96
|
expect do
|
97
97
|
TimeFrame.new(min: Time.utc(2012), duration: 0.seconds)
|
98
98
|
end.not_to raise_error
|
99
99
|
end
|
100
100
|
end
|
101
101
|
end
|
102
|
-
|
103
102
|
end
|
104
103
|
context 'and time sframe covers a DST shift' do
|
105
104
|
let(:time) do
|
@@ -135,14 +134,14 @@ describe TimeFrame do
|
|
135
134
|
it { should eq 0 }
|
136
135
|
end
|
137
136
|
context 'when time frame containts a DST shift' do
|
138
|
-
it '
|
137
|
+
it 'gains 1 hour on summer -> winter shifts' do
|
139
138
|
Time.use_zone('Europe/Berlin') do
|
140
139
|
time_frame = TimeFrame.new(min: Time.zone.local(2013, 10, 27),
|
141
140
|
max: Time.zone.local(2013, 10, 28))
|
142
141
|
expect(time_frame.duration).to eq 25.hours
|
143
142
|
end
|
144
143
|
end
|
145
|
-
it '
|
144
|
+
it 'loses 1 hour on winter -> summer shifts' do
|
146
145
|
Time.use_zone('Europe/Berlin') do
|
147
146
|
time_frame = TimeFrame.new(min: Time.zone.local(2013, 3, 31),
|
148
147
|
max: Time.zone.local(2013, 4, 1))
|
@@ -192,7 +191,7 @@ describe TimeFrame do
|
|
192
191
|
describe '#<=>' do
|
193
192
|
let(:time_frames) do
|
194
193
|
array = TimeFrame.new(min: Time.utc(2014), duration: 30.days)
|
195
|
-
|
194
|
+
.split_by_interval(1.day)
|
196
195
|
time_frame1 = TimeFrame.new(min: Time.utc(2014), duration: 2.days)
|
197
196
|
array << time_frame1
|
198
197
|
array << time_frame1.shift_by(1.day)
|
@@ -408,7 +407,6 @@ describe TimeFrame do
|
|
408
407
|
end
|
409
408
|
|
410
409
|
describe '.union' do
|
411
|
-
|
412
410
|
context 'when given an empty array' do
|
413
411
|
subject { TimeFrame.union([]) }
|
414
412
|
it { should eq [] }
|
@@ -749,7 +747,7 @@ describe TimeFrame do
|
|
749
747
|
expect(subject[day]).to eq expected.shift_by(day.days)
|
750
748
|
end
|
751
749
|
end
|
752
|
-
it '
|
750
|
+
it 'has a smaller time_frame at the end' do
|
753
751
|
expected = TimeFrame.new(min: time + 7.days, duration: 12.hours)
|
754
752
|
expect(subject[7]).to eq expected
|
755
753
|
end
|
@@ -826,7 +824,6 @@ describe TimeFrame do
|
|
826
824
|
end
|
827
825
|
|
828
826
|
describe '#shift_to' do
|
829
|
-
|
830
827
|
let(:duration) { 1.day }
|
831
828
|
let(:min) { Time.zone.local(2012, 1, 2) }
|
832
829
|
let(:max) { min + duration }
|
@@ -1013,7 +1010,6 @@ describe TimeFrame do
|
|
1013
1010
|
end
|
1014
1011
|
|
1015
1012
|
describe '.covering_time_frame_for' do
|
1016
|
-
|
1017
1013
|
context 'for a single time frame' do
|
1018
1014
|
let(:time_frame) { TimeFrame.new(min: time, duration: 1.hour) }
|
1019
1015
|
subject { TimeFrame.covering_time_frame_for([time_frame]) }
|
@@ -1054,7 +1050,6 @@ describe TimeFrame do
|
|
1054
1050
|
end
|
1055
1051
|
|
1056
1052
|
describe '.each_overlap' do
|
1057
|
-
|
1058
1053
|
# Visualization of example input:
|
1059
1054
|
#
|
1060
1055
|
# array1: |---|-------| |-------|-----------|
|
data/time_frame.gemspec
CHANGED
@@ -26,11 +26,11 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
27
27
|
spec.require_paths = ['lib']
|
28
28
|
|
29
|
-
spec.add_development_dependency 'rake', '~> 10.3
|
30
|
-
spec.add_development_dependency 'rspec', '~> 3.0
|
31
|
-
spec.add_development_dependency 'simplecov', '~> 0.8
|
32
|
-
spec.add_development_dependency 'rubocop', '~> 0.23
|
29
|
+
spec.add_development_dependency 'rake', '~> 10.3'
|
30
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
31
|
+
spec.add_development_dependency 'simplecov', '~> 0.8'
|
32
|
+
spec.add_development_dependency 'rubocop', '~> 0.23'
|
33
33
|
spec.add_development_dependency 'sqlite3'
|
34
|
-
spec.add_dependency 'activerecord', '~> 4.
|
35
|
-
spec.add_dependency 'activesupport', '~> 4.
|
34
|
+
spec.add_dependency 'activerecord', '~> 4.2'
|
35
|
+
spec.add_dependency 'activesupport', '~> 4.2'
|
36
36
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: time_frame
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Patrick Derichs
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2014-
|
13
|
+
date: 2014-12-30 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rake
|
@@ -18,56 +18,56 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - "~>"
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 10.3
|
21
|
+
version: '10.3'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
26
|
- - "~>"
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: 10.3
|
28
|
+
version: '10.3'
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
30
|
name: rspec
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
32
32
|
requirements:
|
33
33
|
- - "~>"
|
34
34
|
- !ruby/object:Gem::Version
|
35
|
-
version: 3.0
|
35
|
+
version: '3.0'
|
36
36
|
type: :development
|
37
37
|
prerelease: false
|
38
38
|
version_requirements: !ruby/object:Gem::Requirement
|
39
39
|
requirements:
|
40
40
|
- - "~>"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: 3.0
|
42
|
+
version: '3.0'
|
43
43
|
- !ruby/object:Gem::Dependency
|
44
44
|
name: simplecov
|
45
45
|
requirement: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
47
|
- - "~>"
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version: 0.8
|
49
|
+
version: '0.8'
|
50
50
|
type: :development
|
51
51
|
prerelease: false
|
52
52
|
version_requirements: !ruby/object:Gem::Requirement
|
53
53
|
requirements:
|
54
54
|
- - "~>"
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version: 0.8
|
56
|
+
version: '0.8'
|
57
57
|
- !ruby/object:Gem::Dependency
|
58
58
|
name: rubocop
|
59
59
|
requirement: !ruby/object:Gem::Requirement
|
60
60
|
requirements:
|
61
61
|
- - "~>"
|
62
62
|
- !ruby/object:Gem::Version
|
63
|
-
version: 0.23
|
63
|
+
version: '0.23'
|
64
64
|
type: :development
|
65
65
|
prerelease: false
|
66
66
|
version_requirements: !ruby/object:Gem::Requirement
|
67
67
|
requirements:
|
68
68
|
- - "~>"
|
69
69
|
- !ruby/object:Gem::Version
|
70
|
-
version: 0.23
|
70
|
+
version: '0.23'
|
71
71
|
- !ruby/object:Gem::Dependency
|
72
72
|
name: sqlite3
|
73
73
|
requirement: !ruby/object:Gem::Requirement
|
@@ -88,28 +88,28 @@ dependencies:
|
|
88
88
|
requirements:
|
89
89
|
- - "~>"
|
90
90
|
- !ruby/object:Gem::Version
|
91
|
-
version: 4.
|
91
|
+
version: '4.2'
|
92
92
|
type: :runtime
|
93
93
|
prerelease: false
|
94
94
|
version_requirements: !ruby/object:Gem::Requirement
|
95
95
|
requirements:
|
96
96
|
- - "~>"
|
97
97
|
- !ruby/object:Gem::Version
|
98
|
-
version: 4.
|
98
|
+
version: '4.2'
|
99
99
|
- !ruby/object:Gem::Dependency
|
100
100
|
name: activesupport
|
101
101
|
requirement: !ruby/object:Gem::Requirement
|
102
102
|
requirements:
|
103
103
|
- - "~>"
|
104
104
|
- !ruby/object:Gem::Version
|
105
|
-
version: 4.
|
105
|
+
version: '4.2'
|
106
106
|
type: :runtime
|
107
107
|
prerelease: false
|
108
108
|
version_requirements: !ruby/object:Gem::Requirement
|
109
109
|
requirements:
|
110
110
|
- - "~>"
|
111
111
|
- !ruby/object:Gem::Version
|
112
|
-
version: 4.
|
112
|
+
version: '4.2'
|
113
113
|
description: TimeFrame
|
114
114
|
email:
|
115
115
|
- patrick.derichs@invision.de
|
@@ -131,8 +131,8 @@ files:
|
|
131
131
|
- lib/time_frame/empty.rb
|
132
132
|
- lib/time_frame/time_frame.rb
|
133
133
|
- lib/time_frame/time_frame_covered.rb
|
134
|
-
- lib/time_frame/time_frame_handler.rb
|
135
134
|
- lib/time_frame/time_frame_overlaps.rb
|
135
|
+
- lib/time_frame/time_frame_predicate_builder_handler.rb
|
136
136
|
- lib/time_frame/time_frame_splitter.rb
|
137
137
|
- lib/time_frame/time_frame_uniter.rb
|
138
138
|
- lib/time_frame/tree_node.rb
|
@@ -140,7 +140,7 @@ files:
|
|
140
140
|
- spec/collection_spec.rb
|
141
141
|
- spec/models/vogon_poem.rb
|
142
142
|
- spec/spec_helper.rb
|
143
|
-
- spec/
|
143
|
+
- spec/time_frame_predicate_builder_handler_spec.rb
|
144
144
|
- spec/time_frame_spec.rb
|
145
145
|
- time_frame.gemspec
|
146
146
|
homepage: https://github.com/injixo/time_frame
|
@@ -171,5 +171,5 @@ test_files:
|
|
171
171
|
- spec/collection_spec.rb
|
172
172
|
- spec/models/vogon_poem.rb
|
173
173
|
- spec/spec_helper.rb
|
174
|
-
- spec/
|
174
|
+
- spec/time_frame_predicate_builder_handler_spec.rb
|
175
175
|
- spec/time_frame_spec.rb
|
@@ -1,14 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'models/vogon_poem'
|
3
|
-
|
4
|
-
describe TimeFrame::Handler do
|
5
|
-
let(:time_frame) { TimeFrame.new(min: 5.days.ago, duration: 20.days) }
|
6
|
-
let!(:poem_min) { VogonPoem.create(written_at: time_frame.min) }
|
7
|
-
let!(:poem_max) { VogonPoem.create(written_at: time_frame.max) }
|
8
|
-
|
9
|
-
it 'should return all records between min and max' do
|
10
|
-
expect(VogonPoem.where(written_at: time_frame).count).to eq 2
|
11
|
-
expect(VogonPoem.where(written_at: time_frame).first).to eq poem_min
|
12
|
-
expect(VogonPoem.where(written_at: time_frame).last).to eq poem_max
|
13
|
-
end
|
14
|
-
end
|