time_frame 0.3.0 → 0.4.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 +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
|