slotter 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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