slotter 0.0.1

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/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Bjarki Gudlaugsson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,39 @@
1
+ = Slotter
2
+
3
+ Create and manipulate time slots simply and easily. The gem allows you to perform operations like addition, subtraction and splitting on time slots. Time slots are immutable.
4
+
5
+ == Installation
6
+
7
+ sudo gem install slotter --source http://gemcutter.org
8
+
9
+ == Examples
10
+
11
+ a = TimeSlot.new(Chronic.parse("today 10:00"), Chronic.parse("today 11:00"))
12
+ b = TimeSlot.new(Chronic.parse("today 10:00"), Chronic.parse("today 12:00"))
13
+ c = TimeSlot.new(Chronic.parse("today 11:00"), Chronic.parse("today 12:00"))
14
+
15
+ === Concatenating
16
+
17
+ a + b #=> [#<TimeSlot:0x1018f90b0 @finish=Sun Nov 01 12:00:00 +0000 2009,
18
+ @start=Sun Nov 01 10:00:00 +0000 2009>]
19
+ a + c #=> [#<TimeSlot:0x1018df890 @finish=Sun Nov 01 12:00:00 +0000 2009,
20
+ @start=Sun Nov 01 10:00:00 +0000 2009>]
21
+
22
+ === Subtracting
23
+
24
+ b - a #=> [#<TimeSlot:0x1018d91c0 @finish=Sun Nov 01 12:00:00 +0000 2009,
25
+ @start=Sun Nov 01 11:00:00 +0000 2009>]
26
+ b - c #=> [#<TimeSlot:0x1018dc528 @finish=Sun Nov 01 11:00:00 +0000 2009,
27
+ @start=Sun Nov 01 10:00:00 +0000 2009>]
28
+
29
+ === Splitting
30
+
31
+ b.split(3600) #=>
32
+ [#<TimeSlot:0x1018d57f0 @finish=Sun Nov 01 11:00:00 +0000 2009,
33
+ @start=Sun Nov 01 10:00:00 +0000 2009>,
34
+ #<TimeSlot:0x1018d5728 @finish=Sun Nov 01 12:00:00 +0000 2009,
35
+ @start=Sun Nov 01 11:00:00 +0000 2009>]
36
+
37
+ == Copyright
38
+
39
+ Copyright (c) 2009 Bjarki Gudlaugsson. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "slotter"
8
+ gem.summary = %Q{create and manipulate time slots simply and easily}
9
+ gem.description = %Q{the gem allows you to perform operations like addition, subtraction and splitting on time slots}
10
+ gem.email = "bjarkigud@gmail.com"
11
+ gem.homepage = "http://github.com/bjarkigud/slotter"
12
+ gem.authors = ["Bjarki Gudlaugsson"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ gem.add_development_dependency "chronic", ">= 0.2.3"
15
+ gem.add_development_dependency "cucumber", ">= 0.4.2"
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
21
+ end
22
+
23
+ require 'spec/rake/spectask'
24
+ Spec::Rake::SpecTask.new(:spec) do |spec|
25
+ spec.libs << 'lib' << 'spec'
26
+ spec.spec_files = FileList['spec/**/*_spec.rb']
27
+ end
28
+
29
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
30
+ spec.libs << 'lib' << 'spec'
31
+ spec.pattern = 'spec/**/*_spec.rb'
32
+ spec.rcov = true
33
+ end
34
+
35
+ task :spec => :check_dependencies
36
+
37
+ begin
38
+ require 'cucumber/rake/task'
39
+ Cucumber::Rake::Task.new(:cucumber)
40
+
41
+ task :features => :check_dependencies
42
+ rescue LoadError
43
+ task :features do
44
+ abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
45
+ end
46
+ end
47
+
48
+ task :default => :spec
49
+
50
+ require 'rake/rdoctask'
51
+ Rake::RDocTask.new do |rdoc|
52
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
53
+
54
+ rdoc.rdoc_dir = 'rdoc'
55
+ rdoc.title = "slotter #{version}"
56
+ rdoc.rdoc_files.include('README*')
57
+ rdoc.rdoc_files.include('lib/**/*.rb')
58
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,91 @@
1
+ ##############################
2
+ # Case 1
3
+ # +-----+ +-----+
4
+ # | A | - | B | => nil
5
+ # +-----+ +-----+
6
+ ##############################
7
+ # Case 2
8
+ # +-----+ +-----+
9
+ # | A | | |
10
+ # +-----+ - | B | => nil
11
+ # | |
12
+ # +-----+
13
+ ##############################
14
+ # Case 3
15
+ # +-----+
16
+ # +-----+ | |
17
+ # | A | - | B | => nil
18
+ # +-----+ | |
19
+ # +-----+
20
+ ##############################
21
+ # Case 4
22
+ # +-----+ +-----+ A.start
23
+ # | A | | C |
24
+ # +-----+ - +-----+ => +-----+ A.finish
25
+ # | B |
26
+ # +-----+
27
+ ##############################
28
+ # Case 5
29
+ # +-----+
30
+ # | B |
31
+ # +-----+ - +-----+ => +-----+ A.start
32
+ # | A | | C |
33
+ # +-----+ +-----+ A.finish
34
+ ##############################
35
+ # Case 6
36
+ # +-----+ +-----+ A.start
37
+ # | A | | C |
38
+ # +-----+ +-----+ A.finish
39
+ # - =>
40
+ # +-----+
41
+ # | B |
42
+ # +-----+
43
+ ##############################
44
+ # Case 7
45
+ # +-----+
46
+ # | B |
47
+ # +-----+
48
+ # - =>
49
+ # +-----+ +-----+ A.start
50
+ # | A | | C |
51
+ # +-----+ +-----+ A.finish
52
+ ##############################
53
+ # Case 8
54
+ # +-----+ +-----+
55
+ # | | | B |
56
+ # | A | - +-----+ => +-----+ B.finish
57
+ # | | | C |
58
+ # +-----+ +-----+ A.finish
59
+ ##############################
60
+ # Case 9
61
+ # +-----+ +-----+ A.start
62
+ # | | | C |
63
+ # | A | - +-----+ => +-----+ B.start
64
+ # | | | B |
65
+ # +-----+ +-----+
66
+ ##############################
67
+ # Case 10
68
+ # +-----+ +-----+ A.start
69
+ # | | | C |
70
+ # | | +-----+ +-----+ B.start
71
+ # | A | - | B | =>
72
+ # | | +-----+ +-----+ B.finish
73
+ # | | | C |
74
+ # +-----+ +-----+ A.finish
75
+ ##############################
76
+ # Case 11
77
+ # +-----+ +-----+ A.start
78
+ # | | | |
79
+ # | A | | C |
80
+ # | | - +-----+ => +-----+ B.start
81
+ # +-----+ | B |
82
+ # +-----+
83
+ ##############################
84
+ # Case 12
85
+ # +-----+
86
+ # +-----+ | B |
87
+ # | | - +-----+ => +-----+ B.finish
88
+ # | A | | C |
89
+ # | | | |
90
+ # +-----+ +-----+ A.finish
91
+ ##############################
@@ -0,0 +1,91 @@
1
+ ##############################
2
+ # Case 1
3
+ # +-----+ +-----+ +-----+ A.start
4
+ # | A | + | B | => | C |
5
+ # +-----+ +-----+ +-----+ A.finish
6
+ ##############################
7
+ # Case 2
8
+ # +-----+ +-----+ +-----+ B.start
9
+ # | A | | | | |
10
+ # +-----+ + | B | => | C |
11
+ # | | | |
12
+ # +-----+ +-----+ B.finish
13
+ ##############################
14
+ # Case 3
15
+ # +-----+ +-----+ B.start
16
+ # +-----+ | | | |
17
+ # | A | + | B | => | C |
18
+ # +-----+ | | | |
19
+ # +-----+ +-----+ B.finish
20
+ ##############################
21
+ # Case 4
22
+ # +-----+ +-----+ A.start
23
+ # | A | | |
24
+ # +-----+ + +-----+ => | C |
25
+ # | B | | |
26
+ # +-----+ +-----+ B.finish
27
+ ##############################
28
+ # Case 5
29
+ # +-----+ +-----+ B.start
30
+ # | B | | |
31
+ # +-----+ + +-----+ => | C |
32
+ # | A | | |
33
+ # +-----+ +-----+ A.finish
34
+ ##############################
35
+ # Case 6
36
+ # +-----+ +-----+ A.start
37
+ # | A | | C |
38
+ # +-----+ +-----+ A.finish
39
+ # + =>
40
+ # +-----+ +-----+ B.start
41
+ # | B | | C |
42
+ # +-----+ +-----+ B.finish
43
+ ##############################
44
+ # Case 7
45
+ # +-----+ +-----+ B.start
46
+ # | B | | C |
47
+ # +-----+ +-----+ B.finish
48
+ # + =>
49
+ # +-----+ +-----+ A.start
50
+ # | A | | C |
51
+ # +-----+ +-----+ A.finish
52
+ ##############################
53
+ # Case 8
54
+ # +-----+ +-----+ +-----+ A.start
55
+ # | | | B | | |
56
+ # | A | + +-----+ => | C |
57
+ # | | | |
58
+ # +-----+ +-----+ A.finish
59
+ ##############################
60
+ # Case 9
61
+ # +-----+ +-----+ A.start
62
+ # | | | |
63
+ # | A | + +-----+ => | C |
64
+ # | | | B | | |
65
+ # +-----+ +-----+ +-----+ A.finish
66
+ ##############################
67
+ # Case 10
68
+ # +-----+ +-----+ A.start
69
+ # | | | |
70
+ # | | +-----+ | |
71
+ # | A | + | B | => | C |
72
+ # | | +-----+ | |
73
+ # | | | |
74
+ # +-----+ +-----+ A.finish
75
+ ##############################
76
+ # Case 11
77
+ # +-----+ +-----+ A.start
78
+ # | | | |
79
+ # | A | | |
80
+ # | | + +-----+ => | C |
81
+ # +-----+ | B | | |
82
+ # +-----+ +-----+ B.finish
83
+ ##############################
84
+ # Case 12
85
+ # +-----+ +-----+ B.start
86
+ # +-----+ | B | | |
87
+ # | | + +-----+ => | C |
88
+ # | A | | |
89
+ # | | | |
90
+ # +-----+ +-----+ A.finish
91
+ ##############################
@@ -0,0 +1,48 @@
1
+ Given /^I have a time slot "([^\"]*)" between "([^\"]*)" and "([^\"]*)"$/ do |name, start, finish|
2
+ @time_slots ||= {}
3
+ @time_slots[name] = TimeSlot.new(Chronic.parse("today " + start), Chronic.parse("today " + finish))
4
+ end
5
+
6
+ When /^I subtract time slot "([^\"]*)" from time slot "([^\"]*)"$/ do |a, b|
7
+ @result = @time_slots[b] - @time_slots[a]
8
+ end
9
+
10
+ When /^I add time slot "([^\"]*)" to time slot "([^\"]*)"$/ do |a, b|
11
+ @result = @time_slots[b] + @time_slots[a]
12
+ end
13
+
14
+ When /^I split time slot "([^\"]*)" into ([0-9]+) second slots$/ do |name, duration|
15
+ @result = @time_slots[name].split(duration.to_i)
16
+ end
17
+
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)
21
+ end
22
+
23
+ Then /^I should have an array of ([0-9]+) time slots$/ do |size|
24
+ @result.is_a?(Array).should == true
25
+ @result.length.should == size.to_i
26
+ for slot in @result
27
+ slot.is_a?(TimeSlot).should == true
28
+ end
29
+ end
30
+
31
+ Then /^one should be between "([^\"]*)" and "([^\"]*)"$/ do |start, finish|
32
+ found = false
33
+ for slot in @result
34
+ if slot.start == Chronic.parse("today " + start) and
35
+ slot.finish == Chronic.parse("today " + finish)
36
+ found = true
37
+ end
38
+ end
39
+ found.should == true
40
+ end
41
+
42
+ Then /^I should have nil as a result$/ do
43
+ @result.should == nil
44
+ end
45
+
46
+ Then /^the array should be empty$/ do
47
+ @result.should be_empty
48
+ end
@@ -0,0 +1,5 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
+ require 'spec/expectations'
3
+ require 'rubygems'
4
+ require 'chronic'
5
+ require 'slotter'
@@ -0,0 +1,103 @@
1
+ Feature: Time slot addition
2
+ In order to simplify creating applications based around time slots
3
+ As a developer
4
+ I want to be able to concatenate time slots through code
5
+
6
+ # Case 1
7
+ Scenario: Add a time slot to another where they are equal
8
+ Given I have a time slot "A" between "10:00" and "11:00"
9
+ And I have a time slot "B" between "10:00" and "11:00"
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"
13
+
14
+ # Case 2
15
+ Scenario: Add A.start == B.start
16
+ Given I have a time slot "A" between "10:00" and "11:00"
17
+ And I have a time slot "B" between "10:00" and "12:00"
18
+ 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"
21
+
22
+ # Case 3
23
+ Scenario: Add A.start > B.start and A.finish < B.finish
24
+ Given I have a time slot "A" between "11:00" and "12:00"
25
+ And I have a time slot "B" between "10:00" and "13:00"
26
+ 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"
29
+
30
+ # Case 4
31
+ Scenario: Add A.finish == B.start
32
+ Given I have a time slot "A" between "10:00" and "11:00"
33
+ And I have a time slot "B" between "11:00" and "12:00"
34
+ 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"
37
+
38
+ # Case 5
39
+ Scenario: Add A.start == B.finish
40
+ Given I have a time slot "A" between "11:00" and "12:00"
41
+ And I have a time slot "B" between "10:00" and "11:00"
42
+ 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"
45
+
46
+ # Case 6
47
+ Scenario: Add non-intersecting A.finish < B.start
48
+ Given I have a time slot "A" between "10:00" and "11:00"
49
+ 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"
54
+
55
+ # Case 7
56
+ Scenario: Add non-intersecting A.start > B.finish
57
+ Given I have a time slot "A" between "12:00" and "13:00"
58
+ 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
+
64
+ # Case 8
65
+ Scenario: Add A.start == B.start and A.finish > B.finish
66
+ Given I have a time slot "A" between "10:00" and "12:00"
67
+ And I have a time slot "B" between "10:00" and "11:00"
68
+ 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"
71
+
72
+ # Case 9
73
+ Scenario: Add A.start < B.start and A.finish == B.finish
74
+ Given I have a time slot "A" between "10:00" and "12:00"
75
+ And I have a time slot "B" between "11:00" and "12:00"
76
+ 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"
79
+
80
+ # Case 10
81
+ Scenario: Add A.start < B.start and A.finish > B.finish
82
+ Given I have a time slot "A" between "10:00" and "13:00"
83
+ And I have a time slot "B" between "11:00" and "12:00"
84
+ 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"
87
+
88
+ # Case 11
89
+ Scenario: Add a half intersecting time slot (A.finish < B.finish)
90
+ Given I have a time slot "A" between "10:00" and "12:00"
91
+ And I have a time slot "B" between "11:00" and "13:00"
92
+ 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"
95
+
96
+ # Case 12
97
+ Scenario: Add a half intersecting time slot (A.start > B.start)
98
+ Given I have a time slot "A" between "11:00" and "13:00"
99
+ And I have a time slot "B" between "10:00" and "12:00"
100
+ 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"
103
+
@@ -0,0 +1,5 @@
1
+ Feature: Time slot intersection
2
+ In order to do correct time slot calculations
3
+ As a developer
4
+ I want to be able to identify time slot intersections through code
5
+
@@ -0,0 +1,32 @@
1
+ Feature: Time slot split
2
+ In order to do correct time slot calculations
3
+ As a developer
4
+ I want to be able to split time slots through code
5
+
6
+ Scenario: Split a 1 hour time slot into 1 hour time slots
7
+ Given I have a time slot "A" between "10:00" and "11:00"
8
+ When I split time slot "A" into 3600 second slots
9
+ Then I should have an array of 1 time slots
10
+ And one should be between "10:00" and "11:00"
11
+
12
+ Scenario: Split a 3 hour time slot into 1 hour time slots
13
+ Given I have a time slot "A" between "10:00" and "13:00"
14
+ When I split time slot "A" into 3600 second slots
15
+ Then I should have an array of 3 time slots
16
+ And one should be between "10:00" and "11:00"
17
+ And one should be between "11:00" and "12:00"
18
+ And one should be between "12:00" and "13:00"
19
+
20
+ Scenario: Split a 2 hour and 45 minute time slot into 1 hour time slots
21
+ Given I have a time slot "A" between "10:00" and "12:45"
22
+ When I split time slot "A" into 3600 second slots
23
+ Then I should have an array of 3 time slots
24
+ And one should be between "10:00" and "11:00"
25
+ And one should be between "11:00" and "12:00"
26
+ And one should be between "12:00" and "12:45"
27
+
28
+ Scenario: Split a 30 minute slot into 1 hour time slots
29
+ Given I have a time slot "A" between "10:00" and "10:30"
30
+ When I split time slot "A" into 3600 second slots
31
+ Then I should have an array of 1 time slots
32
+ And one should be between "10:00" and "10:30"
@@ -0,0 +1,99 @@
1
+ Feature: Time slot subtraction
2
+ In order to simplify creating applications based around time slots
3
+ As a developer
4
+ I want to be able to subtract time slots through code
5
+
6
+ # Case 1
7
+ Scenario: Subtract a time slot from another where they are equal
8
+ Given I have a time slot "A" between "10:00" and "11:00"
9
+ And I have a time slot "B" between "10:00" and "11:00"
10
+ When I subtract time slot "B" from time slot "A"
11
+ Then I should have an array of 0 time slots
12
+
13
+ # Case 2
14
+ Scenario: Subtract a large time slot from a small time slot with equal start
15
+ Given I have a time slot "A" between "10:00" and "11:00"
16
+ And I have a time slot "B" between "10:00" and "12:00"
17
+ When I subtract time slot "B" from time slot "A"
18
+ Then I should have an array of 0 time slots
19
+
20
+ # Case 3
21
+ Scenario: Subtract a bigger time slot from a smaller
22
+ Given I have a time slot "A" between "11:00" and "12:00"
23
+ And I have a time slot "B" between "10:00" and "13:00"
24
+ When I subtract time slot "B" from time slot "A"
25
+ Then I should have an array of 0 time slots
26
+
27
+ # Case 4
28
+ Scenario: Subtract non-intersecting A.finish == B.start
29
+ Given I have a time slot "A" between "10:00" and "11:00"
30
+ And I have a time slot "B" between "11:00" and "12:00"
31
+ When I subtract time slot "B" from time slot "A"
32
+ Then I should have an array of 1 time slots
33
+ And one should be between "10:00" and "11:00"
34
+
35
+ # Case 5
36
+ Scenario: Subtract non-intersecting A.start == B.finish
37
+ Given I have a time slot "A" between "11:00" and "12:00"
38
+ And I have a time slot "B" between "10:00" and "11:00"
39
+ When I subtract time slot "B" from time slot "A"
40
+ Then I should have an array of 1 time slots
41
+ And one should be between "11:00" and "12:00"
42
+
43
+ # Case 6
44
+ Scenario: Subtract non-intersecting A.finish < B.start
45
+ Given I have a time slot "A" between "10:00" and "11:00"
46
+ And I have a time slot "B" between "12:00" and "13:00"
47
+ When I subtract time slot "B" from time slot "A"
48
+ Then I should have an array of 1 time slots
49
+ And one should be between "10:00" and "11:00"
50
+
51
+ # Case 7
52
+ Scenario: Subtract non-intersecting A.start > B.finish
53
+ Given I have a time slot "A" between "12:00" and "13:00"
54
+ And I have a time slot "B" between "10:00" and "11:00"
55
+ When I subtract time slot "B" from time slot "A"
56
+ Then I should have an array of 1 time slots
57
+ And one should be between "12:00" and "13:00"
58
+
59
+ # Case 8
60
+ Scenario: Subtract a small time slot from a bit time slot when start is equal
61
+ Given I have a time slot "A" between "10:00" and "12:00"
62
+ And I have a time slot "B" between "10:00" and "11:00"
63
+ When I subtract time slot "B" from time slot "A"
64
+ Then I should have an array of 1 time slots
65
+ And one should be between "11:00" and "12:00"
66
+
67
+ # Case 9
68
+ Scenario: Subtract a small time slot from a big time slot when finish is equal
69
+ Given I have a time slot "A" between "10:00" and "12:00"
70
+ And I have a time slot "B" between "11:00" and "12:00"
71
+ When I subtract time slot "B" from time slot "A"
72
+ Then I should have an array of 1 time slots
73
+ And one should be between "10:00" and "11:00"
74
+
75
+ # Case 10
76
+ Scenario: Subtract a contained time slot
77
+ Given I have a time slot "A" between "10:00" and "13:00"
78
+ And I have a time slot "B" between "11:00" and "12:00"
79
+ When I subtract time slot "B" from time slot "A"
80
+ Then I should have an array of 2 time slots
81
+ And one should be between "10:00" and "11:00"
82
+ And one should be between "12:00" and "13:00"
83
+
84
+ # Case 11
85
+ Scenario: Subtract a half intersecting time slot (A.finish < B.finish)
86
+ Given I have a time slot "A" between "10:00" and "12:00"
87
+ And I have a time slot "B" between "11:00" and "13:00"
88
+ When I subtract time slot "B" from time slot "A"
89
+ Then I should have an array of 1 time slots
90
+ And one should be between "10:00" and "11:00"
91
+
92
+ # Case 12
93
+ Scenario: Subtract a half intersecting time slot (A.start > B.start)
94
+ Given I have a time slot "A" between "11:00" and "13:00"
95
+ And I have a time slot "B" between "10:00" and "12:00"
96
+ When I subtract time slot "B" from time slot "A"
97
+ Then I should have an array of 1 time slots
98
+ And one should be between "12:00" and "13:00"
99
+
@@ -0,0 +1,154 @@
1
+ # A TimeSlot object holds the start date and finish date of a period in time
2
+ class TimeSlot
3
+ include Comparable
4
+ attr_reader :start, :finish
5
+
6
+ def initialize(start, finish)
7
+ @start = start
8
+ @finish = finish
9
+ end
10
+
11
+ # Returns the difference between start and finish of the TimeSlot in seconds
12
+ def duration
13
+ (self.finish - self.start)
14
+ end
15
+
16
+ # Subtraction---Returns a set of new TimeSlot(s) that are the result of
17
+ # removing the other_slot from this slot.
18
+ def -(other_slot)
19
+ # Case 1, Case 2 or Case 3
20
+ if (self.start == other_slot.start and self.finish == other_slot.finish) or
21
+ (self.start == other_slot.start and self.finish < other_slot.finish) or
22
+ (self.start > other_slot.start and self.finish < other_slot.finish)
23
+ return []
24
+ end
25
+ # Case 4, Case 5, Case 6 or Case 7
26
+ if (self.finish == other_slot.start) or
27
+ (self.start == other_slot.finish) or
28
+ (self.finish < other_slot.start) or
29
+ (self.start > other_slot.finish)
30
+ return [self.clone]
31
+ end
32
+ # Case 8
33
+ if self.start == other_slot.start and self.finish > other_slot.finish
34
+ return [TimeSlot.new(other_slot.finish, self.finish)]
35
+ end
36
+ # Case 9 or Case 11
37
+ if (self.start < other_slot.start and self.finish == other_slot.finish) or
38
+ (self.start < other_slot.start and self.finish < other_slot.finish and self.finish > other_slot.start)
39
+ return [TimeSlot.new(self.start, other_slot.start)]
40
+ end
41
+ # Case 10
42
+ if self.start < other_slot.start and self.finish > other_slot.finish
43
+ return [TimeSlot.new(self.start, other_slot.start),
44
+ TimeSlot.new(other_slot.finish, self.finish)]
45
+ end
46
+ # Case 12
47
+ if self.start > other_slot.start and self.finish > other_slot.finish and self.start < other_slot.finish
48
+ return [TimeSlot.new(other_slot.finish, self.finish)]
49
+ end
50
+ end
51
+
52
+ # Concatenation---Returns a set of new TimeSlot(s) that are the result of
53
+ # concatenating the other_slot to this slot.
54
+ def +(other_slot)
55
+ # Case 1
56
+ if self.start == other_slot.start and self.finish == other_slot.finish
57
+ return [self.clone]
58
+ end
59
+ # Case 2 or Case 3
60
+ if (self.start == other_slot.start and self.finish < other_slot.finish) or
61
+ (self.start > other_slot.start and self.finish < other_slot.finish)
62
+ return [other_slot.clone]
63
+ end
64
+ # Case 4
65
+ if self.finish == other_slot.start
66
+ return [TimeSlot.new(self.start, other_slot.finish)]
67
+ end
68
+ # Case 5
69
+ if self.start == other_slot.finish
70
+ return [TimeSlot.new(other_slot.start, self.finish)]
71
+ end
72
+ # Case 6 or Case 7
73
+ if (self.finish < other_slot.start) or
74
+ (self.start > other_slot.finish)
75
+ return [self.clone, other_slot.clone].sort!
76
+ end
77
+ # Case 8, Case 9 or Case 10
78
+ if (self.start == other_slot.start and self.finish > other_slot.finish) or
79
+ (self.start < other_slot.start and self.finish == other_slot.finish) or
80
+ (self.start < other_slot.start and self.finish > other_slot.finish)
81
+ return [self.clone]
82
+ end
83
+ # Case 11
84
+ 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)]
86
+ end
87
+ # Case 12
88
+ 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)]
90
+ end
91
+ end
92
+
93
+ # Equality---Two time slots are equal if they have the same start and finish
94
+ def ==(other_slot)
95
+ (self.start == other_slot.start and self.finish == other_slot.finish)
96
+ end
97
+
98
+ # Comparison---Returns an integer (-1, 0,
99
+ # or +1) if this time slot is less than, equal to, or greater than
100
+ # other_slot. First we compare the start of both slots and if they are equal
101
+ # then we compare the finish of both slots. Thus, two arrays are ``equal''
102
+ # according to <code>TimeSlot#<=></code> if an only if they have the same
103
+ # start and finish.
104
+ #
105
+ # today_at_nine = Chronic.parse("today 09:00")
106
+ # today_at_ten = Chronic.parse("today 10:00")
107
+ # today_at_eleven = Chronic.parse("today 11:00")
108
+ #
109
+ # a = TimeSlot.new(today_at_nine, today_at_ten)
110
+ # b = TimeSlot.new(today_at_ten, today_at_eleven)
111
+ # c = TimeSlot.new(today_at_nine, today_at_eleven)
112
+ #
113
+ # a <=> b #=> -1
114
+ # a <=> c #=> -1
115
+ # b <=> c #=> +1
116
+ #
117
+ def <=>(other_slot)
118
+ cmp = self.start <=> other_slot.start
119
+ (cmp == 0) ? self.finish <=> other_slot.finish : cmp
120
+ end
121
+
122
+ # Split this time slot into a set of new TimeSlot(s) where the duration of
123
+ # each slot is equal to or smaller than <i>length</i>.
124
+ #
125
+ # The duration of the last slot in the result will be set to the remainder if
126
+ # the this time slot cannot be divided equally based on <i>length</i>.
127
+ #
128
+ # a = TimeSlot.new(Chronic.parse("today 10:00"), Chronic.parse("today 12:30"))
129
+ #
130
+ # a.split(3600) #=> [
131
+ # #<TimeSlot:0x1018cf3a0 @start=Sun Nov 01 10:00:00 +0000 2009,
132
+ # @finish=Sun Nov 01 11:00:00 +0000 2009>,
133
+ # #<TimeSlot:0x1018cf260 @start=Sun Nov 01 11:00:00 +0000 2009,
134
+ # @finish=Sun Nov 01 12:00:00 +0000 2009>,
135
+ # #<TimeSlot:0x1018cf198 @start=Sun Nov 01 12:00:00 +0000 2009,
136
+ # @finish=Sun Nov 01 12:30:00 +0000 2009>]
137
+ #
138
+ def split(length)
139
+ result = []
140
+ if self.duration <= length
141
+ result << self.clone
142
+ else
143
+ current = TimeSlot.new(self.start, self.start + length)
144
+ result << current
145
+ result += (self - current)[0].split(length)
146
+ end
147
+ return result
148
+ end
149
+
150
+ # Shows the start and end of this TimeSlot
151
+ def to_s
152
+ "#{self.start} to #{self.finish}"
153
+ end
154
+ end
data/lib/slotter.rb ADDED
@@ -0,0 +1,2 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+ require 'slotter/time_slot'
data/slotter.gemspec ADDED
@@ -0,0 +1,70 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{slotter}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Bjarki Gudlaugsson"]
12
+ s.date = %q{2009-11-01}
13
+ s.description = %q{the gem allows you to perform operations like addition, subtraction and splitting on time slots}
14
+ s.email = %q{bjarkigud@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "features/case_subtraction.txt",
27
+ "features/cases_addition.txt",
28
+ "features/step_definitions/time_slot_definitions.rb",
29
+ "features/support/env.rb",
30
+ "features/time_slot_addition.feature",
31
+ "features/time_slot_intersection.feature",
32
+ "features/time_slot_split.feature",
33
+ "features/time_slot_subtraction.feature",
34
+ "lib/slotter.rb",
35
+ "lib/slotter/time_slot.rb",
36
+ "slotter.gemspec",
37
+ "spec/spec.opts",
38
+ "spec/spec_helper.rb",
39
+ "spec/time_slot_spec.rb"
40
+ ]
41
+ s.homepage = %q{http://github.com/bjarkigud/slotter}
42
+ s.rdoc_options = ["--charset=UTF-8"]
43
+ s.require_paths = ["lib"]
44
+ s.rubygems_version = %q{1.3.5}
45
+ s.summary = %q{create and manipulate time slots simply and easily}
46
+ s.test_files = [
47
+ "spec/spec_helper.rb",
48
+ "spec/time_slot_spec.rb"
49
+ ]
50
+
51
+ if s.respond_to? :specification_version then
52
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
53
+ s.specification_version = 3
54
+
55
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
56
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
57
+ s.add_development_dependency(%q<chronic>, [">= 0.2.3"])
58
+ s.add_development_dependency(%q<cucumber>, [">= 0.4.2"])
59
+ else
60
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
61
+ s.add_dependency(%q<chronic>, [">= 0.2.3"])
62
+ s.add_dependency(%q<cucumber>, [">= 0.4.2"])
63
+ end
64
+ else
65
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
66
+ s.add_dependency(%q<chronic>, [">= 0.2.3"])
67
+ s.add_dependency(%q<cucumber>, [">= 0.4.2"])
68
+ end
69
+ end
70
+
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format specdoc
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,11 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'slotter'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+ require 'rubygems'
7
+ require 'chronic'
8
+
9
+ Spec::Runner.configure do |config|
10
+
11
+ end
@@ -0,0 +1,4 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe TimeSlot do
4
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: slotter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Bjarki Gudlaugsson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-01 00:00:00 +00:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.9
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: chronic
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.2.3
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: cucumber
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.4.2
44
+ version:
45
+ description: the gem allows you to perform operations like addition, subtraction and splitting on time slots
46
+ email: bjarkigud@gmail.com
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ extra_rdoc_files:
52
+ - LICENSE
53
+ - README.rdoc
54
+ files:
55
+ - .document
56
+ - .gitignore
57
+ - LICENSE
58
+ - README.rdoc
59
+ - Rakefile
60
+ - VERSION
61
+ - features/case_subtraction.txt
62
+ - features/cases_addition.txt
63
+ - features/step_definitions/time_slot_definitions.rb
64
+ - features/support/env.rb
65
+ - features/time_slot_addition.feature
66
+ - features/time_slot_intersection.feature
67
+ - features/time_slot_split.feature
68
+ - features/time_slot_subtraction.feature
69
+ - lib/slotter.rb
70
+ - lib/slotter/time_slot.rb
71
+ - slotter.gemspec
72
+ - spec/spec.opts
73
+ - spec/spec_helper.rb
74
+ - spec/time_slot_spec.rb
75
+ has_rdoc: true
76
+ homepage: http://github.com/bjarkigud/slotter
77
+ licenses: []
78
+
79
+ post_install_message:
80
+ rdoc_options:
81
+ - --charset=UTF-8
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: "0"
89
+ version:
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: "0"
95
+ version:
96
+ requirements: []
97
+
98
+ rubyforge_project:
99
+ rubygems_version: 1.3.5
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: create and manipulate time slots simply and easily
103
+ test_files:
104
+ - spec/spec_helper.rb
105
+ - spec/time_slot_spec.rb