time_frame 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/time_frame/collection.rb +52 -50
- data/lib/time_frame/tree_node.rb +44 -44
- data/lib/time_frame/version.rb +1 -1
- data/spec/collection_spec.rb +5 -5
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef554cd54e51a1fc22a6c16b6cf1bac7b43b19d8
|
4
|
+
data.tar.gz: 319e9ef2ced0c9ec7f4fe221cc22c4e48743a2a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac152a3d12403ee212d374f1282f2ec3d63cc39d223d6e292680e8ea6e45fbcb55b1b465319fa0d8bfb448d6b33a444e53d74c4341aacfee8fe2f1a737bd9333
|
7
|
+
data.tar.gz: a5a439ab393e88bcef9195d632c8b774e7c88f538e9bce1efea20ace56ba76c182f5cf3d8deb43cf0e77f36d50e1b5357682000418321872fdc2fed072b8869b
|
@@ -1,68 +1,70 @@
|
|
1
1
|
# Encoding: utf-8
|
2
2
|
|
3
|
-
|
4
|
-
#
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
3
|
+
class TimeFrame
|
4
|
+
# This collection supports the concept of interval trees to improve the
|
5
|
+
# access speed to intervals (or objects containing intervals) intersecting
|
6
|
+
# given time_frames or covering time elements
|
7
|
+
class Collection
|
8
|
+
attr_reader :tree_nodes, :root
|
9
|
+
def initialize(item_list = [], sorted = false, &block)
|
10
|
+
@block = block ? block : ->(item) { item }
|
11
|
+
@tree_nodes = item_list.map do |item|
|
12
|
+
TreeNode.new(item: item, &@block)
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
sort_list(@tree_nodes) unless sorted
|
16
|
+
build_tree(0, @tree_nodes.size - 1)
|
17
|
+
@root = @tree_nodes[(@tree_nodes.size - 1) / 2]
|
18
|
+
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
def all_covering(time)
|
21
|
+
result = []
|
22
|
+
add_covering(time, @root, result)
|
23
|
+
result.sort_by { |item | [@block.call(item).min, @block.call(item).max] }
|
24
|
+
end
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
def all_intersecting(time_frame)
|
27
|
+
result = []
|
28
|
+
add_intersecting(time_frame, @root, result)
|
29
|
+
result.sort_by { |item | [@block.call(item).min, @block.call(item).max] }
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
+
private
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
34
|
+
def sort_list(item_list)
|
35
|
+
item_list.sort_by! do |item|
|
36
|
+
[item.time_frame.min, item.time_frame.max]
|
37
|
+
end
|
36
38
|
end
|
37
|
-
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
def build_tree(lower, upper, ancestor = nil, side = nil)
|
41
|
+
mid = (lower + upper) / 2
|
42
|
+
node = @tree_nodes[mid]
|
42
43
|
|
43
|
-
|
44
|
+
node.update_ancestor_relation(ancestor, side) if ancestor && side
|
44
45
|
|
45
|
-
|
46
|
-
|
46
|
+
build_tree(lower, mid - 1, node, :left) unless lower == mid
|
47
|
+
build_tree(mid + 1, upper, node, :right) unless upper == mid
|
47
48
|
|
48
|
-
|
49
|
-
|
49
|
+
node.update_child_frame(node.child_time_frame) if lower == upper
|
50
|
+
end
|
50
51
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
def add_covering(time, node, result)
|
53
|
+
result << node.item if node.time_frame.cover?(time)
|
54
|
+
if node.continue_left_side_search_for_time?(time)
|
55
|
+
add_covering(time, node.left_child, result)
|
56
|
+
end
|
57
|
+
return unless node.continue_right_side_search_for_time?(time)
|
58
|
+
add_covering(time, node.right_child, result)
|
55
59
|
end
|
56
|
-
return unless node.continue_right_side_search_for_time?(time)
|
57
|
-
add_covering(time, node.right_child, result)
|
58
|
-
end
|
59
60
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
61
|
+
def add_intersecting(time_frame, node, result)
|
62
|
+
result << node.item unless (node.time_frame & time_frame).empty?
|
63
|
+
if node.continue_left_side_search_for_time_frame?(time_frame)
|
64
|
+
add_intersecting(time_frame, node.left_child, result)
|
65
|
+
end
|
66
|
+
return unless node.continue_right_side_search_for_time_frame?(time_frame)
|
67
|
+
add_intersecting(time_frame, node.right_child, result)
|
64
68
|
end
|
65
|
-
return unless node.continue_right_side_search_for_time_frame?(time_frame)
|
66
|
-
add_intersecting(time_frame, node.right_child, result)
|
67
69
|
end
|
68
70
|
end
|
data/lib/time_frame/tree_node.rb
CHANGED
@@ -1,55 +1,55 @@
|
|
1
1
|
# Encoding: utf-8
|
2
|
-
class
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
2
|
+
class TimeFrame
|
3
|
+
class Collection
|
4
|
+
# This is a helper class for the collection. It contains the node definition
|
5
|
+
# for the used tree structues.
|
6
|
+
class TreeNode
|
7
|
+
attr_accessor :left_child, :right_child, :child_time_frame
|
8
|
+
attr_reader :item, :time_frame, :ancestor
|
9
|
+
def initialize(args, &block)
|
10
|
+
@item = args.fetch(:item)
|
11
|
+
@time_frame = block.call(item)
|
12
|
+
# if ancestor is nil, then tree_item is root node
|
13
|
+
@ancestor = args.fetch(:ancestor, nil)
|
14
|
+
@left_child = args.fetch(:left_child, nil)
|
15
|
+
@right_child = args.fetch(:right_child, nil)
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
17
|
+
# if block is given use it to get item's time frame
|
18
|
+
@child_time_frame = @time_frame
|
19
|
+
end
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
def update_ancestor_relation(new_ancestor, side)
|
22
|
+
@ancestor = new_ancestor
|
23
|
+
new_ancestor.left_child = self if side == :left
|
24
|
+
new_ancestor.right_child = self if side == :right
|
25
|
+
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
27
|
+
def update_child_frame(new_child_frame)
|
28
|
+
min = [@child_time_frame.min, new_child_frame.min].min
|
29
|
+
max = [@child_time_frame.max, new_child_frame.max].max
|
30
|
+
@child_time_frame = TimeFrame.new(min: min, max: max)
|
31
|
+
ancestor.update_child_frame(@child_time_frame) if ancestor
|
32
|
+
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
34
|
+
def continue_left_side_search_for_time?(time)
|
35
|
+
left_child && left_child.child_time_frame.cover?(time)
|
36
|
+
end
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
def continue_left_side_search_for_time_frame?(interval)
|
39
|
+
left_child &&
|
40
|
+
left_child.child_time_frame.min <= interval.max &&
|
41
|
+
left_child.child_time_frame.max >= interval.min
|
42
|
+
end
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
44
|
+
def continue_right_side_search_for_time?(time)
|
45
|
+
right_child && right_child.child_time_frame.cover?(time)
|
46
|
+
end
|
48
47
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
48
|
+
def continue_right_side_search_for_time_frame?(interval)
|
49
|
+
right_child &&
|
50
|
+
right_child.child_time_frame.min <= interval.max &&
|
51
|
+
right_child.child_time_frame.max >= interval.min
|
52
|
+
end
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
data/lib/time_frame/version.rb
CHANGED
data/spec/collection_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Collection do
|
3
|
+
describe TimeFrame::Collection do
|
4
4
|
|
5
5
|
let(:time_frame) { TimeFrame.new(min: Time.utc(2014), duration: 20.days) }
|
6
6
|
let(:time) { Time.utc(2014) }
|
@@ -9,7 +9,7 @@ describe Collection do
|
|
9
9
|
context 'when a pure time_frame tree is given' do
|
10
10
|
it 'returns all covering time_frames' do
|
11
11
|
time_frames = 20.times.map { |i| time_frame.shift_by((5 * i).days) }
|
12
|
-
tree = Collection.new(time_frames)
|
12
|
+
tree = TimeFrame::Collection.new(time_frames)
|
13
13
|
|
14
14
|
result = tree.all_covering(time)
|
15
15
|
expected_result = time_frames.select { |t| t.cover?(time) }
|
@@ -44,7 +44,7 @@ describe Collection do
|
|
44
44
|
objects = 20.times.map do |i|
|
45
45
|
OpenStruct.new(time_frame: time_frame.shift_by((5 * i).days))
|
46
46
|
end
|
47
|
-
tree = Collection.new(objects) { |item| item.time_frame }
|
47
|
+
tree = TimeFrame::Collection.new(objects) { |item| item.time_frame }
|
48
48
|
|
49
49
|
result = tree.all_covering(time - 1.day)
|
50
50
|
expect(result).to eq []
|
@@ -83,7 +83,7 @@ describe Collection do
|
|
83
83
|
context 'when a pure time_frame tree is given' do
|
84
84
|
it 'returns all intersecting time_frames' do
|
85
85
|
time_frames = 20.times.map { |i| time_frame.shift_by((5 * i).days) }
|
86
|
-
tree = Collection.new(time_frames)
|
86
|
+
tree = TimeFrame::Collection.new(time_frames)
|
87
87
|
interval = TimeFrame.new(min: time, duration: 1.hour)
|
88
88
|
|
89
89
|
result = tree.all_intersecting(interval.shift_by((-1).day))
|
@@ -133,7 +133,7 @@ describe Collection do
|
|
133
133
|
objects = 20.times.map do |i|
|
134
134
|
OpenStruct.new(time_frame: time_frame.shift_by((5 * i).days))
|
135
135
|
end
|
136
|
-
tree = Collection.new(objects) { |item| item.time_frame }
|
136
|
+
tree = TimeFrame::Collection.new(objects) { |item| item.time_frame }
|
137
137
|
interval = TimeFrame.new(min: time, duration: 1.hour)
|
138
138
|
|
139
139
|
result = tree.all_intersecting(interval.shift_by((-1).day))
|
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.
|
4
|
+
version: 0.4.0
|
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-10-
|
13
|
+
date: 2014-10-14 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rake
|