slotter 0.0.2 → 0.0.3

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.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
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 an array of 1 time slots
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 an array of 1 time slots
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 an array of 1 time slots
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 an array of 1 time slots
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 an array of 1 time slots
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
- When I add time slot "B" to time slot "A"
51
- Then I should have an array of 1 time slots
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
- When I add time slot "B" to time slot "A"
60
- Then I should have an array of 2 time slots
61
- And one should be between "10:00" and "11:00"
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 an array of 1 time slots
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 an array of 1 time slots
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 an array of 1 time slots
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 an array of 1 time slots
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 an array of 1 time slots
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
+
@@ -1,2 +1,3 @@
1
1
  $:.unshift File.dirname(__FILE__)
2
- require 'slotter/time_slot'
2
+ require 'slotter/time_slot'
3
+ require 'slotter/time_slot_collection'
@@ -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 [self.clone]
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 [other_slot.clone]
103
+ return other_slot.clone
63
104
  end
64
105
  # Case 4
65
106
  if self.finish == other_slot.start
66
- return [TimeSlot.new(self.start, other_slot.finish)]
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 [TimeSlot.new(other_slot.start, self.finish)]
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
- return [self.clone, other_slot.clone].sort!
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 [self.clone]
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 [TimeSlot.new(self.start, other_slot.finish)]
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 [TimeSlot.new(other_slot.start, self.finish)]
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
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{slotter}
8
- s.version = "0.0.2"
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-01}
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.2
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-01 00:00:00 +00:00
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