timeline-manager 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/lib/EventedArray.rb +25 -0
- data/lib/TimeObj.rb +51 -0
- data/lib/timeline-manager.rb +132 -0
- metadata +46 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8da990d4583655335ad676d2a17af7a6474f1a14c49707c313c7089ad0af3fea
|
4
|
+
data.tar.gz: d817ddc51240341c721631ea9203d9f13a73f1d36e8b453d35f435e405393a0c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a07e9f3627aed54ffe1c952ed061b82c55add602d6ef08fda4f3449bb77c07e571aa0c049e4d6781d87f7b0d8aae846e45573f6ce6478e95bad7c9481e559810
|
7
|
+
data.tar.gz: 44d7b7ecd229e12269cd507f9d7389ea9f8a23a66099b13100e9511f110c2618d82fd10d3a617d389238e0f27d988a1dbd1eaff194f06ccc976a244cdc105745
|
data/lib/EventedArray.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
class EventedArray < Array
|
2
|
+
# The calling context knows whether an element has been
|
3
|
+
# created, deleted or updated.
|
4
|
+
# This class is to be used in an append-only environment.
|
5
|
+
|
6
|
+
def initialize(post_delete, post_create, post_update)
|
7
|
+
@post_delete = post_delete
|
8
|
+
@post_create = post_create
|
9
|
+
@post_update = post_update
|
10
|
+
end
|
11
|
+
|
12
|
+
def delete(data)
|
13
|
+
@post_destroy.call(data)
|
14
|
+
end
|
15
|
+
|
16
|
+
def create(data)
|
17
|
+
self << data
|
18
|
+
@post_create.call(data)
|
19
|
+
end
|
20
|
+
|
21
|
+
def update(data)
|
22
|
+
self << data
|
23
|
+
@post_update.call(data)
|
24
|
+
end
|
25
|
+
end
|
data/lib/TimeObj.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'active_support/core_ext/object'
|
2
|
+
|
3
|
+
class TimeObj
|
4
|
+
# An interface to deal with passed-in time objects which
|
5
|
+
# may have a variety of interfaces.
|
6
|
+
|
7
|
+
include Comparable
|
8
|
+
|
9
|
+
attr_reader :data
|
10
|
+
attr_reader :start_method
|
11
|
+
attr_reader :end_method
|
12
|
+
|
13
|
+
def initialize(data, start_method=:start, end_method=:end)
|
14
|
+
if data.respond_to? :each
|
15
|
+
@data = data
|
16
|
+
else
|
17
|
+
@data = [data]
|
18
|
+
end
|
19
|
+
if @data.class == Range || @data.class == Array
|
20
|
+
start_method = :first
|
21
|
+
end_method = :last
|
22
|
+
end
|
23
|
+
@start_method = start_method
|
24
|
+
@end_method = end_method
|
25
|
+
end
|
26
|
+
|
27
|
+
def <=>(other)
|
28
|
+
@data <=> other.data
|
29
|
+
end
|
30
|
+
|
31
|
+
def start
|
32
|
+
@data[@start_method]
|
33
|
+
end
|
34
|
+
|
35
|
+
def end
|
36
|
+
@data[@end_method]
|
37
|
+
end
|
38
|
+
|
39
|
+
def merge(params)
|
40
|
+
if @data.respond_to? :attributes
|
41
|
+
return @data.class.new(@data.attributes.merge(params))
|
42
|
+
elsif @data.respond_to? :merge
|
43
|
+
return @data.merge(params)
|
44
|
+
end
|
45
|
+
raise ArgumentError.new('Objects that are represented as times must respond to :attributes or :merge.')
|
46
|
+
end
|
47
|
+
|
48
|
+
def duration
|
49
|
+
self.end - start
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'active_support/core_ext/object'
|
2
|
+
require 'TimeObj'
|
3
|
+
require 'EventedArray'
|
4
|
+
|
5
|
+
module TimelineManager
|
6
|
+
class Timeline
|
7
|
+
|
8
|
+
def initialize(times=[], time_diff: Proc.new { 1.day }, start_method: :start,
|
9
|
+
end_method: :end, post_delete: Proc.new{}, post_create: Proc.new{},
|
10
|
+
post_update: Proc.new{})
|
11
|
+
@times = times.map { |t| t.class == TimeObj ? t : TimeObj.new(t, start_method, end_method) }
|
12
|
+
@time_diff = time_diff
|
13
|
+
@start_method = start_method
|
14
|
+
@end_method = end_method
|
15
|
+
@post_delete = post_delete
|
16
|
+
@post_create = post_create
|
17
|
+
@post_update = post_update
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
data
|
22
|
+
end
|
23
|
+
|
24
|
+
def inspect
|
25
|
+
"TimelineManager::Timeline##{self.object_id} #{to_s}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def data
|
29
|
+
@times.map { |t| t.data }
|
30
|
+
end
|
31
|
+
|
32
|
+
def insert(time, time_diff: Proc.new { 1.day }, start_method: :start,
|
33
|
+
end_method: :end, post_delete: nil, post_create: nil,
|
34
|
+
post_update: nil)
|
35
|
+
# Produce a new Timeline where time's start through end is unique in @times.
|
36
|
+
time = TimeObj.new(time, start_method, end_method)
|
37
|
+
new_times = EventedArray.new((post_delete || @post_delete), (post_create || @post_create), (post_update || @post_update))
|
38
|
+
@times.each do |t|
|
39
|
+
if t.start >= time.start && t.end <= time.end
|
40
|
+
# The new time covers the old one completely; remove it.
|
41
|
+
new_times.delete t
|
42
|
+
elsif t.start < time.start && t.end > time.end
|
43
|
+
# The new time splits the old one in half.
|
44
|
+
new_times.update t.merge({"#{t.end_method}": time.start - time_diff.call})
|
45
|
+
new_times.update t.merge({"#{t.start_method}": time.end + time_diff.call})
|
46
|
+
elsif t.start < time.start
|
47
|
+
# The new time cuts off the old time's end.
|
48
|
+
new_times.update t.merge({"#{t.end_method}": time.start - time_diff.call })
|
49
|
+
else
|
50
|
+
# The new time cuts off the old time's beginning.
|
51
|
+
new_times.update t.merge({"#{t.start_method}": time.end + time_diff.call })
|
52
|
+
end
|
53
|
+
end
|
54
|
+
new_times.create time
|
55
|
+
Timeline.new(new_times, time_diff: @time_diff, start_method: @start_method,
|
56
|
+
end_method: @end_method, post_delete: @post_delete, post_create: @post_create,
|
57
|
+
post_update: @post_update)
|
58
|
+
end
|
59
|
+
|
60
|
+
def overlap(time, time_diff: Proc.new { 1.day }, start_method: :start,
|
61
|
+
end_method: :end, post_delete: nil, post_create: nil,
|
62
|
+
post_update: nil)
|
63
|
+
# Beginning and end overlap, but middle is replaced.
|
64
|
+
time = TimeObj.new(time, start_method, end_method)
|
65
|
+
new_times = EventedArray.new((post_delete || @post_delete), (post_create || @post_create), (post_update || @post_update))
|
66
|
+
@times.each do |t|
|
67
|
+
if t.start > time.start && t.end < time.end
|
68
|
+
# The new time covers the old one completely; remove it.
|
69
|
+
new_times.delete t
|
70
|
+
elsif t.start <= time.start && t.end >= time.end
|
71
|
+
# The new time splits the old one in half.
|
72
|
+
if time.duration > time_diff.call
|
73
|
+
# The new time is more than one time_diff long
|
74
|
+
new_times.update t.merge({"#{t.start_method}": time.end})
|
75
|
+
new_times.update t.merge({"#{t.end_method}": time.start})
|
76
|
+
end
|
77
|
+
elsif t.start < time.start
|
78
|
+
# The new time cuts off the old time's end.
|
79
|
+
new_times.update t.merge({"#{t.end_method}": time.start})
|
80
|
+
elsif t.start == time.start && time.end >= t.end
|
81
|
+
# The new time starts on the old time's start, but the new time continues past the time's end
|
82
|
+
new_times.update t.merge({"#{t.end_method}": t.start})
|
83
|
+
else
|
84
|
+
# The new time cuts off the old time's beginning.
|
85
|
+
new_times.update t.merge({"#{t.start_method}": time.end})
|
86
|
+
end
|
87
|
+
end
|
88
|
+
new_times.create time
|
89
|
+
Timeline.new(new_times, time_diff: @time_diff, start_method: @start_method,
|
90
|
+
end_method: @end_method, post_delete: @post_delete, post_create: @post_create,
|
91
|
+
post_update: @post_update)
|
92
|
+
end
|
93
|
+
|
94
|
+
def overlay(time, start_method: :start, end_method: :end, post_delete: nil)
|
95
|
+
# Simply add the new time to the time line; allows complete overlap.
|
96
|
+
new_times = EventedArray.new((post_delete || @post_delete), (post_create || @post_create), (post_update || @post_update))
|
97
|
+
new_times << @times
|
98
|
+
new_times.create time
|
99
|
+
Timeline.new(new_times, time_diff: time_diff, start_method: @start_method,
|
100
|
+
end_method: @end_method, post_delete: @post_delete, post_create: @post_create,
|
101
|
+
post_update: @post_update)
|
102
|
+
end
|
103
|
+
|
104
|
+
def split(date, time_diff: Proc.new { 1.day }, post_update: nil)
|
105
|
+
# Splits timelines in half given a point in time.
|
106
|
+
time = TimeObj.new({start: date, end: date + time_diff.call})
|
107
|
+
new_times = EventedArray.new(@post_delete, @post_create, (post_update || @post_update))
|
108
|
+
@times.each do |t|
|
109
|
+
if t.start > time.start && t.end < time.end
|
110
|
+
# The new time covers the old one completely.
|
111
|
+
new_times << t
|
112
|
+
elsif t.start <= time.start && t.end >= time.end
|
113
|
+
# The new time splits the old one in half.
|
114
|
+
new_times.update t.merge({"#{t.start_method}": time.end})
|
115
|
+
new_times.update t.merge({"#{t.end_method}": time.start})
|
116
|
+
elsif t.start < time.start
|
117
|
+
# The new time cuts off the old time's end.
|
118
|
+
new_times.update t.merge({"#{t.end_method}": time.start})
|
119
|
+
elsif t.start == time.start && time.end >= t.end
|
120
|
+
# The new time starts on the old time's start, but the new time continues past the time's end
|
121
|
+
new_times.update t.merge({"#{t.end_method}": t.start})
|
122
|
+
else
|
123
|
+
# The new time cuts off the old time's beginning.
|
124
|
+
new_times.update t.merge({"#{t.start_method}": time.end})
|
125
|
+
end
|
126
|
+
end
|
127
|
+
Timeline.new(new_times, time_diff: @time_diff, start_method: @start_method,
|
128
|
+
end_method: @end_method, post_delete: @post_delete, post_create: @post_create,
|
129
|
+
post_update: @post_update)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
metadata
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: timeline-manager
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tyler Brothers
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-08-24 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: ''
|
14
|
+
email: tylerbrothers1@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/EventedArray.rb
|
20
|
+
- lib/TimeObj.rb
|
21
|
+
- lib/timeline-manager.rb
|
22
|
+
homepage: https://github.com/possibly/timeline-manager
|
23
|
+
licenses:
|
24
|
+
- MIT
|
25
|
+
metadata: {}
|
26
|
+
post_install_message:
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
29
|
+
- lib
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubyforge_project:
|
42
|
+
rubygems_version: 2.7.7
|
43
|
+
signing_key:
|
44
|
+
specification_version: 4
|
45
|
+
summary: Timeline Manager helps order and transform grouped temporal data
|
46
|
+
test_files: []
|