slotter 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/features/step_definitions/time_slot_collection_definitions.rb +24 -0
- data/features/step_definitions/time_slot_definitions.rb +11 -3
- data/features/time_slot_addition.feature +15 -29
- data/features/time_slot_collection_compress.feature +19 -0
- data/features/time_slot_collection_merge.feature +22 -0
- data/lib/slotter.rb +2 -1
- data/lib/slotter/time_slot.rb +51 -10
- data/lib/slotter/time_slot_collection.rb +74 -0
- data/slotter.gemspec +6 -2
- metadata +6 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Given /^I have a time slot collection "([^\"]*)"$/ do |name|
|
2
|
+
@time_slot_collections ||= {}
|
3
|
+
@time_slot_collections[name] = TimeSlotCollection.new
|
4
|
+
end
|
5
|
+
|
6
|
+
Given /^time slot "([^\"]*)" belongs to collection "([^\"]*)"$/ do |slot, collection|
|
7
|
+
@time_slot_collections[collection] << @time_slots[slot]
|
8
|
+
end
|
9
|
+
|
10
|
+
When /^I merge time slot collections "([^\"]*)" and "([^\"]*)"$/ do |a, b|
|
11
|
+
@result = @time_slot_collections[a].merge(@time_slot_collections[b])
|
12
|
+
end
|
13
|
+
|
14
|
+
When /^I compress time slot collection "([^\"]*)"$/ do |name|
|
15
|
+
@result = @time_slot_collections[name].compress
|
16
|
+
end
|
17
|
+
|
18
|
+
Then /^I should have a new collection of ([0-9]+) time slots$/ do |length|
|
19
|
+
@result.time_slots.length.should == length.to_i
|
20
|
+
end
|
21
|
+
|
22
|
+
Then /^show the result$/ do
|
23
|
+
puts "The result is: \n#{@result}"
|
24
|
+
end
|
@@ -16,8 +16,8 @@ When /^I split time slot "([^\"]*)" into ([0-9]+) second slots$/ do |name, durat
|
|
16
16
|
end
|
17
17
|
|
18
18
|
Then /^I should have a time slot between "([^\"]*)" and "([^\"]*)"$/ do |start, finish|
|
19
|
-
@result.start.should == Chronic.parse(start)
|
20
|
-
@result.finish.should == Chronic.parse(finish)
|
19
|
+
@result.start.should == Chronic.parse("today " + start)
|
20
|
+
@result.finish.should == Chronic.parse("today " + finish)
|
21
21
|
end
|
22
22
|
|
23
23
|
Then /^I should have an array of ([0-9]+) time slots$/ do |size|
|
@@ -45,4 +45,12 @@ end
|
|
45
45
|
|
46
46
|
Then /^the array should be empty$/ do
|
47
47
|
@result.should be_empty
|
48
|
-
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Then /^"([^\"]*)" and "([^\"]*)" should be disjoint$/ do |a, b|
|
51
|
+
@time_slots[a].disjoint?(@time_slots[b]).should == true
|
52
|
+
end
|
53
|
+
|
54
|
+
Then /^I should not be able to add "([^\"]*)" to "([^\"]*)"$/ do |a, b|
|
55
|
+
(@time_slots[a] + @time_slots[b]).should == nil
|
56
|
+
end
|
@@ -8,96 +8,82 @@ Feature: Time slot addition
|
|
8
8
|
Given I have a time slot "A" between "10:00" and "11:00"
|
9
9
|
And I have a time slot "B" between "10:00" and "11:00"
|
10
10
|
When I add time slot "B" to time slot "A"
|
11
|
-
Then I should have
|
12
|
-
Then one should be between "10:00" and "11:00"
|
11
|
+
Then I should have a time slot between "10:00" and "11:00"
|
13
12
|
|
14
13
|
# Case 2
|
15
14
|
Scenario: Add A.start == B.start
|
16
15
|
Given I have a time slot "A" between "10:00" and "11:00"
|
17
16
|
And I have a time slot "B" between "10:00" and "12:00"
|
18
17
|
When I add time slot "B" to time slot "A"
|
19
|
-
Then I should have
|
20
|
-
Then one should be between "10:00" and "12:00"
|
18
|
+
Then I should have a time slot between "10:00" and "12:00"
|
21
19
|
|
22
20
|
# Case 3
|
23
21
|
Scenario: Add A.start > B.start and A.finish < B.finish
|
24
22
|
Given I have a time slot "A" between "11:00" and "12:00"
|
25
23
|
And I have a time slot "B" between "10:00" and "13:00"
|
26
24
|
When I add time slot "B" to time slot "A"
|
27
|
-
Then I should have
|
28
|
-
Then one should be between "10:00" and "13:00"
|
25
|
+
Then I should have a time slot between "10:00" and "13:00"
|
29
26
|
|
30
27
|
# Case 4
|
31
28
|
Scenario: Add A.finish == B.start
|
32
29
|
Given I have a time slot "A" between "10:00" and "11:00"
|
33
30
|
And I have a time slot "B" between "11:00" and "12:00"
|
34
31
|
When I add time slot "B" to time slot "A"
|
35
|
-
Then I should have
|
36
|
-
Then one should be between "10:00" and "12:00"
|
32
|
+
Then I should have a time slot between "10:00" and "12:00"
|
37
33
|
|
38
34
|
# Case 5
|
39
35
|
Scenario: Add A.start == B.finish
|
40
36
|
Given I have a time slot "A" between "11:00" and "12:00"
|
41
37
|
And I have a time slot "B" between "10:00" and "11:00"
|
42
38
|
When I add time slot "B" to time slot "A"
|
43
|
-
Then I should have
|
44
|
-
Then one should be between "10:00" and "12:00"
|
39
|
+
Then I should have a time slot between "10:00" and "12:00"
|
45
40
|
|
46
41
|
# Case 6
|
47
42
|
Scenario: Add non-intersecting A.finish < B.start
|
48
43
|
Given I have a time slot "A" between "10:00" and "11:00"
|
49
44
|
And I have a time slot "B" between "12:00" and "13:00"
|
50
|
-
|
51
|
-
|
52
|
-
And one should be between "10:00" and "11:00"
|
53
|
-
And one should be between "12:00" and "13:00"
|
45
|
+
Then "A" and "B" should be disjoint
|
46
|
+
And I should not be able to add "B" to "A"
|
54
47
|
|
55
48
|
# Case 7
|
56
49
|
Scenario: Add non-intersecting A.start > B.finish
|
57
50
|
Given I have a time slot "A" between "12:00" and "13:00"
|
58
51
|
And I have a time slot "B" between "10:00" and "11:00"
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
And one should be between "12:00" and "13:00"
|
63
|
-
|
52
|
+
Then "A" and "B" should be disjoint
|
53
|
+
And I should not be able to add "B" to "A"
|
54
|
+
|
64
55
|
# Case 8
|
65
56
|
Scenario: Add A.start == B.start and A.finish > B.finish
|
66
57
|
Given I have a time slot "A" between "10:00" and "12:00"
|
67
58
|
And I have a time slot "B" between "10:00" and "11:00"
|
68
59
|
When I add time slot "B" to time slot "A"
|
69
|
-
Then I should have
|
70
|
-
And one should be between "10:00" and "12:00"
|
60
|
+
Then I should have a time slot between "10:00" and "12:00"
|
71
61
|
|
72
62
|
# Case 9
|
73
63
|
Scenario: Add A.start < B.start and A.finish == B.finish
|
74
64
|
Given I have a time slot "A" between "10:00" and "12:00"
|
75
65
|
And I have a time slot "B" between "11:00" and "12:00"
|
76
66
|
When I add time slot "B" to time slot "A"
|
77
|
-
Then I should have
|
78
|
-
And one should be between "10:00" and "12:00"
|
67
|
+
Then I should have a time slot between "10:00" and "12:00"
|
79
68
|
|
80
69
|
# Case 10
|
81
70
|
Scenario: Add A.start < B.start and A.finish > B.finish
|
82
71
|
Given I have a time slot "A" between "10:00" and "13:00"
|
83
72
|
And I have a time slot "B" between "11:00" and "12:00"
|
84
73
|
When I add time slot "B" to time slot "A"
|
85
|
-
Then I should have
|
86
|
-
And one should be between "10:00" and "13:00"
|
74
|
+
Then I should have a time slot between "10:00" and "13:00"
|
87
75
|
|
88
76
|
# Case 11
|
89
77
|
Scenario: Add a half intersecting time slot (A.finish < B.finish)
|
90
78
|
Given I have a time slot "A" between "10:00" and "12:00"
|
91
79
|
And I have a time slot "B" between "11:00" and "13:00"
|
92
80
|
When I add time slot "B" to time slot "A"
|
93
|
-
Then I should have
|
94
|
-
And one should be between "10:00" and "13:00"
|
81
|
+
Then I should have a time slot between "10:00" and "13:00"
|
95
82
|
|
96
83
|
# Case 12
|
97
84
|
Scenario: Add a half intersecting time slot (A.start > B.start)
|
98
85
|
Given I have a time slot "A" between "11:00" and "13:00"
|
99
86
|
And I have a time slot "B" between "10:00" and "12:00"
|
100
87
|
When I add time slot "B" to time slot "A"
|
101
|
-
Then I should have
|
102
|
-
And one should be between "10:00" and "13:00"
|
88
|
+
Then I should have a time slot between "10:00" and "13:00"
|
103
89
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Feature: Time slot collection compress
|
2
|
+
In order to compress collections of time slots
|
3
|
+
As a developer
|
4
|
+
I want to be able to compress a time slot collection through code
|
5
|
+
|
6
|
+
Scenario: compress time slot collection
|
7
|
+
Given I have a time slot collection "X"
|
8
|
+
And I have a time slot "A" between "09:00" and "10:00"
|
9
|
+
And I have a time slot "B" between "09:00" and "14:00"
|
10
|
+
And I have a time slot "C" between "15:00" and "16:00"
|
11
|
+
And I have a time slot "D" between "10:00" and "11:00"
|
12
|
+
And time slot "A" belongs to collection "X"
|
13
|
+
And time slot "B" belongs to collection "X"
|
14
|
+
And time slot "C" belongs to collection "X"
|
15
|
+
And time slot "B" belongs to collection "X"
|
16
|
+
When I compress time slot collection "X"
|
17
|
+
Then I should have a new collection of 2 time slots
|
18
|
+
And one should be between "09:00" and "14:00"
|
19
|
+
And one should be between "15:00" and "16:00"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Feature: Time slot collection merge
|
2
|
+
In order to merge sets of time slots
|
3
|
+
As a developer
|
4
|
+
I want to be able to merge sets of time slots through code
|
5
|
+
|
6
|
+
Scenario: merge a set of time slots with another
|
7
|
+
Given I have a time slot collection "X"
|
8
|
+
And I have a time slot collection "Y"
|
9
|
+
And I have a time slot "A" between "09:00" and "10:00"
|
10
|
+
And I have a time slot "B" between "09:00" and "11:00"
|
11
|
+
And I have a time slot "C" between "13:00" and "13:30"
|
12
|
+
And I have a time slot "D" between "13:30" and "17:00"
|
13
|
+
And time slot "A" belongs to collection "X"
|
14
|
+
And time slot "B" belongs to collection "Y"
|
15
|
+
And time slot "C" belongs to collection "Y"
|
16
|
+
And time slot "D" belongs to collection "X"
|
17
|
+
When I merge time slot collections "X" and "Y"
|
18
|
+
Then I should have a new collection of 2 time slots
|
19
|
+
And one should be between "09:00" and "11:00"
|
20
|
+
And one should be between "13:00" and "17:00"
|
21
|
+
|
22
|
+
|
data/lib/slotter.rb
CHANGED
data/lib/slotter/time_slot.rb
CHANGED
@@ -13,9 +13,48 @@ class TimeSlot
|
|
13
13
|
(self.finish - self.start)
|
14
14
|
end
|
15
15
|
|
16
|
+
# Returns true if this TimeSlot intersects with <i>other_slot</i> otherwise
|
17
|
+
# false.
|
18
|
+
def intersects_with?(other_slot)
|
19
|
+
!disjoint?(other_slot)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns true if this TimeSlot does not intersect with <i>other_slot</i>
|
23
|
+
# otherwise false.
|
24
|
+
def disjoint?(other_slot)
|
25
|
+
(self.start > other_slot.finish) or
|
26
|
+
(self.finish < other_slot.start)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns true if this TimeSlot contains the <i>other_slot</i> otherwise
|
30
|
+
# false.
|
31
|
+
def contains?(other_slot)
|
32
|
+
(self.contains_start_of?(other_slot) and
|
33
|
+
self.contains_finish_of?(other_slot))
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns true if this TimeSlot is within the <i>other_slot</i> otherwise
|
37
|
+
# false.
|
38
|
+
def within?(other_slot)
|
39
|
+
other_slot.contains?(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns true if this TimeSlot contains the start of <i>other_slot</i>
|
43
|
+
# otherwise false.
|
44
|
+
def contains_start_of?(other_slot)
|
45
|
+
(self.start < other_slot.start and self.finish > other_slot.start)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns true if this TimeSlot contains the finish of <i>other_slot</i>
|
49
|
+
# otherwise false.
|
50
|
+
def contains_finish_of?(other_slot)
|
51
|
+
(self.start < other_slot.finish and self.finish > other_slot.finish)
|
52
|
+
end
|
53
|
+
|
16
54
|
# Subtraction---Returns a set of new TimeSlot(s) that are the result of
|
17
55
|
# removing the other_slot from this slot.
|
18
56
|
def -(other_slot)
|
57
|
+
return self unless other_slot
|
19
58
|
# Case 1, Case 2 or Case 3
|
20
59
|
if (self.start == other_slot.start and self.finish == other_slot.finish) or
|
21
60
|
(self.start == other_slot.start and self.finish < other_slot.finish) or
|
@@ -50,43 +89,45 @@ class TimeSlot
|
|
50
89
|
end
|
51
90
|
|
52
91
|
# Concatenation---Returns a set of new TimeSlot(s) that are the result of
|
53
|
-
# concatenating the other_slot to this slot.
|
92
|
+
# concatenating the other_slot to this slot. Returns nil if the slots are
|
93
|
+
# disjoint.
|
54
94
|
def +(other_slot)
|
95
|
+
return self unless other_slot
|
55
96
|
# Case 1
|
56
97
|
if self.start == other_slot.start and self.finish == other_slot.finish
|
57
|
-
return
|
98
|
+
return self.clone
|
58
99
|
end
|
59
100
|
# Case 2 or Case 3
|
60
101
|
if (self.start == other_slot.start and self.finish < other_slot.finish) or
|
61
102
|
(self.start > other_slot.start and self.finish < other_slot.finish)
|
62
|
-
return
|
103
|
+
return other_slot.clone
|
63
104
|
end
|
64
105
|
# Case 4
|
65
106
|
if self.finish == other_slot.start
|
66
|
-
return
|
107
|
+
return TimeSlot.new(self.start, other_slot.finish)
|
67
108
|
end
|
68
109
|
# Case 5
|
69
110
|
if self.start == other_slot.finish
|
70
|
-
return
|
111
|
+
return TimeSlot.new(other_slot.start, self.finish)
|
71
112
|
end
|
72
|
-
# Case 6 or Case 7
|
113
|
+
# Case 6 or Case 7 (Disjoint)
|
73
114
|
if (self.finish < other_slot.start) or
|
74
115
|
(self.start > other_slot.finish)
|
75
|
-
|
116
|
+
return nil
|
76
117
|
end
|
77
118
|
# Case 8, Case 9 or Case 10
|
78
119
|
if (self.start == other_slot.start and self.finish > other_slot.finish) or
|
79
120
|
(self.start < other_slot.start and self.finish == other_slot.finish) or
|
80
121
|
(self.start < other_slot.start and self.finish > other_slot.finish)
|
81
|
-
return
|
122
|
+
return self.clone
|
82
123
|
end
|
83
124
|
# Case 11
|
84
125
|
if self.start < other_slot.start and self.finish < other_slot.finish and self.finish > other_slot.start
|
85
|
-
return
|
126
|
+
return TimeSlot.new(self.start, other_slot.finish)
|
86
127
|
end
|
87
128
|
# Case 12
|
88
129
|
if self.start > other_slot.start and self.finish > other_slot.finish and self.start < other_slot.finish
|
89
|
-
return
|
130
|
+
return TimeSlot.new(other_slot.start, self.finish)
|
90
131
|
end
|
91
132
|
end
|
92
133
|
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# A TimeSlotCollection object holds a collection of TimeSlot objects
|
2
|
+
class TimeSlotCollection
|
3
|
+
attr_reader :time_slots
|
4
|
+
|
5
|
+
# Returns a new collection of time slots where the default is empty.
|
6
|
+
def initialize(time_slots = [])
|
7
|
+
@time_slots = Array.new(time_slots)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Append---Pushes <i>slot</i> to the end of the internal collection of
|
11
|
+
# <i>time_slots</i> if <i>slot</i> is not already a part of it. This
|
12
|
+
# expression returns <i>self</i>, so several appends may be chained together.
|
13
|
+
def <<(slot)
|
14
|
+
@time_slots << slot unless @time_slots.include?(slot)
|
15
|
+
return self
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns a new collection that contains all slots from <i>self</i> and
|
19
|
+
# <i>other_collection</i>.
|
20
|
+
def union(other_collection)
|
21
|
+
result = self.clone
|
22
|
+
for slot in other_collection.time_slots
|
23
|
+
result << slot
|
24
|
+
end
|
25
|
+
return result
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns a copy of <i>self</i> where all intersecting slots have been
|
29
|
+
# joined.
|
30
|
+
#
|
31
|
+
# x = [09:00 to 13:00, 12:00 to 14:00]
|
32
|
+
#
|
33
|
+
# x.compress #=> [09:00 to 14:00]
|
34
|
+
#
|
35
|
+
def compress
|
36
|
+
result = TimeSlotCollection.new
|
37
|
+
for slot_a in @time_slots
|
38
|
+
current_slot = slot_a
|
39
|
+
for slot_b in @time_slots
|
40
|
+
current_slot += slot_b unless current_slot.disjoint?(slot_b)
|
41
|
+
end
|
42
|
+
result << current_slot
|
43
|
+
end
|
44
|
+
return result
|
45
|
+
end
|
46
|
+
|
47
|
+
# Joins all intersecting slots in time_slots. Returns nil if no changes
|
48
|
+
# where made.
|
49
|
+
def compress!
|
50
|
+
result = self.compress.time_slots
|
51
|
+
(result == @time_slots)? nil : self
|
52
|
+
end
|
53
|
+
|
54
|
+
# Creates a new collection that contains the compressed union of
|
55
|
+
# <i>self</i>.time_slots and <i>other_collection</i>.time_slots.
|
56
|
+
def merge(other_collection)
|
57
|
+
self.union(other_collection).compress
|
58
|
+
end
|
59
|
+
|
60
|
+
# Calls <i>block</i> once for each element in <i>self</i>.time_slots, passing
|
61
|
+
# that element as a parameter.
|
62
|
+
def each(&block)
|
63
|
+
for slot in time_slots
|
64
|
+
yield(slot)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
alias :+ :merge
|
69
|
+
|
70
|
+
# Returns <i>self</i>.time_slots.to_s
|
71
|
+
def to_s
|
72
|
+
"#{@time_slots}"
|
73
|
+
end
|
74
|
+
end
|
data/slotter.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{slotter}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Bjarki Gudlaugsson"]
|
12
|
-
s.date = %q{2009-11-
|
12
|
+
s.date = %q{2009-11-03}
|
13
13
|
s.description = %q{the gem allows you to perform operations like addition, subtraction and splitting on time slots}
|
14
14
|
s.email = %q{bjarkigud@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -25,14 +25,18 @@ Gem::Specification.new do |s|
|
|
25
25
|
"VERSION",
|
26
26
|
"features/case_subtraction.txt",
|
27
27
|
"features/cases_addition.txt",
|
28
|
+
"features/step_definitions/time_slot_collection_definitions.rb",
|
28
29
|
"features/step_definitions/time_slot_definitions.rb",
|
29
30
|
"features/support/env.rb",
|
30
31
|
"features/time_slot_addition.feature",
|
32
|
+
"features/time_slot_collection_compress.feature",
|
33
|
+
"features/time_slot_collection_merge.feature",
|
31
34
|
"features/time_slot_intersection.feature",
|
32
35
|
"features/time_slot_split.feature",
|
33
36
|
"features/time_slot_subtraction.feature",
|
34
37
|
"lib/slotter.rb",
|
35
38
|
"lib/slotter/time_slot.rb",
|
39
|
+
"lib/slotter/time_slot_collection.rb",
|
36
40
|
"slotter.gemspec",
|
37
41
|
"spec/spec.opts",
|
38
42
|
"spec/spec_helper.rb",
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: slotter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bjarki Gudlaugsson
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
12
|
+
date: 2009-11-03 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -60,14 +60,18 @@ files:
|
|
60
60
|
- VERSION
|
61
61
|
- features/case_subtraction.txt
|
62
62
|
- features/cases_addition.txt
|
63
|
+
- features/step_definitions/time_slot_collection_definitions.rb
|
63
64
|
- features/step_definitions/time_slot_definitions.rb
|
64
65
|
- features/support/env.rb
|
65
66
|
- features/time_slot_addition.feature
|
67
|
+
- features/time_slot_collection_compress.feature
|
68
|
+
- features/time_slot_collection_merge.feature
|
66
69
|
- features/time_slot_intersection.feature
|
67
70
|
- features/time_slot_split.feature
|
68
71
|
- features/time_slot_subtraction.feature
|
69
72
|
- lib/slotter.rb
|
70
73
|
- lib/slotter/time_slot.rb
|
74
|
+
- lib/slotter/time_slot_collection.rb
|
71
75
|
- slotter.gemspec
|
72
76
|
- spec/spec.opts
|
73
77
|
- spec/spec_helper.rb
|